<?php
// ----------------------------------------------------------------------
// zCart Shopping Cart Module for Zikula
// http://www.zcart.info
// Based on pnCommerce 0.99
// ----------------------------------------------------------------------
// Source file:  $Source: W:\dev\pnuserapi.php $
//
// Last changes from:  $Author: Floxxx $
//
// Revision:           $Revision: 0.1 $
//
// Date of revision    $Date: 6/17/2009 7:06:37 AM $
//
// ----------------------------------------------------------------------
// LICENSE
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// To read the license please visit http://www.gnu.org/copyleft/gpl.html
// ----------------------------------------------------------------------
//		UserAPI functions
// ----------------------------------------------------------------------

require_once('modules/zCart/common.php');

/**
 * Generates a url with the given parameters using the standard
 * pnmodurl and if needed replaces the beginning with https or the sslpath
 *
 *****************
 * THIS IS JUST A SHORT FORM FOR THE ORIGINAL FUNCTION
 * ALL CALLS TO THIS FUNCTION MUST BE REPLACED IN THE LONG TERM!
 * FOR NEW CODE ALWAYS USE THE API CALL FOR
 * PNCOMMERCE_USERAPI_PNCMODURL!
 *****************
 *
 * @param $Module string The modulename
 * @param $Section string section like admin or user
 * @param $Function string the function to call
 * @param $Args array the array of arguments for the Function
 * @return string the generated URL
 */
function pncUserAPIModURL($Module,$Section,$Function,$Args=array())
{
    if (!pnModAPILoad('zCart', 'user'))
    {
        return showerrorpage("unable to load pnuserapi", __FILE__, __LINE__);
    }
    return pnModAPIFunc ('zCart', 'user','pncModURL',
                            array(
                            'Module'=>$Module,
                            'Section'=>$Section,
                            'Function'=>$Function,
                            'Args'=>$Args));
}

/**
 * returns the security level as integer.
 * 0 = no SSL, 1 = only checkout, 2 = Fort Knox, ...
 * @return int
 */
function zCart_userapi_getSecurityLevel()
{
//we should read a config here
  return 1;
}

/**
 * returns the SSL Status the actual url
 * true: when SSL is turned of or SSL is turned on for this page and page is loaded with SSL
 * false: otherwise
 *
 * THIS FUNCTION IS ALSO USED IN URL GENERATION, TO DECIDE
 * IF A URL SHOULD BE IN SSL_MODE!
 * SO, IF 'test' IS SET TO true AND SSL IS TURNED OFF IN THE CONFIG
 * THIS FUNCTION RETURNS false!
 *
 * @param $args['Module'] optional string The modulename, when not given zCart is used
 * @param $args['Section'] string section like admin or user
 * @param $args['Function'] string the function to call
 * @param $args['Args'] array the array of arguments for the Function
 * @param $args['test'] bool, optional when true, this function returns the desired SSL-status of the function: args['Function']
 * @return boolean
 */
function zCart_userapi_SSLStatus($args)
{
    $result=false;
    extract($args);
    if (!pnModAPILoad('zCart', 'admin'))
    {
        return showerrorpage("unable to load pnadminapi", __FILE__, __LINE__);
    }
    //get Security level
    $secLevel=zCart_userapi_getSecurityLevel();
    $SSLConfig = pnModAPIFunc ('zCart', 'admin','getConfigSSL');
    // mod the url
    if (isset($SSLConfig['UseSSL']) && $SSLConfig['UseSSL'] != "on") {
        //SSL is set off
        $result= false;
    }
    else if($secLevel==2)
    {
        //Fort Knox - SSL everywhere
       $result=true;
    }
    else if($secLevel==1){//Medium - SSL on checkout
//functions involved in the checkoutprocess
        $result=($Section=="user")&&(($Function=="userinfo")
                                    || ($Function=="userinforesponse")
                                    || ($Function=="getpaymethod")
                                    || ($Function=="getpaymethodresponse")
                                    || ($Function=="getshippingmethod")
                                    || ($Function=="getshippingmethodresponse")
                                    || ($Function=="checkout")
                                    || ($Function=="checkoutresponse")
                                    || ($Function=="processpaymentfinal")
                                    || ($Function=="processshippingfinal")
                                    || ($Function=="processpaymethod")
                                    || ($Function=="processpaymethodresponse")
                                    || ($Function=="processshippingmethod")
                                    || ($Function=="processshippingmethodresponse")
                                    || ($Function=="receipt")
                                    ||($Function=="order"));
// echo"<pre>";print_r($args); echo"</pre>";  if($result===false)echo "nv ";else echo "jo ";
    }
    else if($secLevel==0)
    {
        //None - never SSL
       $result=false;
    }
//When we're testing for the desired status we don't need to care about the real status
//because we use this for URL generation then
    if( !( isset($args['test']) && ($args['test']===true) ) )
    {
        //not perfect, but should work
        $isSSL=ereg("https://", pnGetBaseURL());
        $result=($isSSL&&$result)||!$result;
    }
    return $result;
}

/**
 * Generates a url with the given parameters using the standard
 * pnmodurl and if needed replaces the beginning with https or the sslpath
 * !!!!!!!!!!!!!!!!!
 * This function needs the new rewritten pnModURL from our includes directory.
 * replace your pnMod.php with our. This patch will be part of the next PN release.
 * !!!!!!!!!!!!!!!!!
 * @param $args['Module'] optional string The modulename, when not given zCart is used
 * @param $args['Section'] string section like admin or user
 * @param $args['Function'] string the function to call
 * @param $args['Args'] array the array of arguments for the Function
 * @return string the generated URL
 */
function zCart_userapi_pncModURL($args)
{
    if(!isset($args['Module']))$args['Module']='zCart';
    if(!isset($args['Args']))$args['Args']=array();
    if (!pnModAPILoad('zCart', 'admin'))
    {
        return showerrorpage("unable to load pnadminapi", __FILE__, __LINE__);
    }
    extract($args);
    $SSLConfig = pnModAPIFunc ('zCart', 'admin','getConfigSSL');
    // mod the url
    if (isset($SSLConfig['UseSSL']) && $SSLConfig['UseSSL'] == "on") {
    //check, if we need to generate a SSL URL
        $SSLSargs=$args;
        $SSLSargs['test']=true;
        $ssl=zCart_userapi_SSLStatus($SSLSargs);
    }else $ssl=false;
//  generates a SSLed URL when $ssl is true.
    $url=pnModURL($Module, $Section, $Function, $Args,$ssl);

/*    //This SSLPath thing is for the first time something PNC specific
    //pnModURL gives us a https url, when we're in SSLMode
    //On some Servers we need this SSLPath as replacement for the baseURL
    if (isset($SSLConfig['UseSSL']) && $SSLConfig['UseSSL'] == "on")
    {
        if (isset($SSLConfig['SSLPath'])&&($SSLConfig['SSLPath'] != ""))
        {
	         // replace with the SSLPath in the config
             //use the 0-9 for example: 127.0.0.1 ( u can also use something like that in the config: https://127.0..0.1)
             //$url = ereg_replace("^(https://([0-9a-z.-]*))", $SSLConfig['SSLPath'], $url);
	         preg_match("/[^\/]+$/",$url,$match);
            $url = $SSLConfig['SSLPath'] . $match[0];
        }
    }*/
    return $url;
}

/*
 * ClearOldCart
 * removes the cart contents older than pnModGetVar('zCart', 'MaximumCartLifetime) minutes
 *
 *@param none
 *@returns none
 */

function zCart_userapi_ClearOldCart()
{
    $result = zCart_userapi_readmultiplefromDB (array('table' => 'cartitems',
                                                           'fields' => array( 'Date', 'CartItemsID', 'UserID' ),
                                                           'required' => array() ) );
    if ( $result <> false )
    {
        foreach($result as $resultline)
        {
            list( $CartDate, $CartItemID, $UserID ) = $resultline;
            $MaxLifeTime=pnModGetVar('zCart', 'MaximumCartLifetime');
            if( $MaxLifeTime == 0 ) $MaxLifeTime = 120;
            if ( time() >= ( $CartDate + ( $MaxLifeTime * 60 ) ) )
            {
                pnModAPIFunc( 'zCart', 'user', 'removeItemfromCart',
                              array( 'CartItemID' => $CartItemID,
                                     'KID'        => $UserID ) );
            }
        }
        zCart_userapi_AddLogMessage( array( 'level' => _PNC_LOG_DEBUG, 'text' => 'cart has been cleared' ) );
    }
}

/**
 * categorylist
 * prepares an array with
 * [0] array of CIDs
 * [1] array of category names
 * [2] number of categories
 * that are in the given category id
 *
 *@param $args['CPa'] int CategoryID (the "parent category")
 *@returns array (see above)
 */

function zCart_userapi_categorylist($args)
{

    echo "Calling an obsolete function - pnc stopped!!";
    die();

/*
    extract($args);
    $num_items = 0;
    $result= zCart_userapi_readmultiplefromDB( array( 'table' => 'category',
                                                           'fields' => array('CategoryID', 'Category'),
                                                           'required' => array('CatParent', $CPa, 'CatInvisible', '')));
    if ( $result <> false )
    {
        $num_items = count($result);
        if ( $num_items )
        {
            foreach ($result as $resultline)
            {
                list ($CID, $Cat) = $resultline;
                if (pnSecAuthAction(0, 'zCart::category', $Cat.'::'.$CID, ACCESS_OVERVIEW))
                {
                    $catlist0[] = $CID;
                    $catlist1[] = $Cat;
                }
            }
            array_multisort($catlist1, SORT_STRING, SORT_ASC, $catlist0);
        }
    }
    $cat_array = array($catlist0, $catlist1, $num_items);
    return $cat_array;
*/
}

/**
 * internal use only
 *
 * build_select
 * build the SELECT part for an sql statement
 *@param $fields (array of columnname(s) that will be read)
 *@returns string
 */
function build_select ($fields)
{
      if (count($fields) > 0)
      {
            // sql will contain the fields to read
            $sql = "SELECT ";
            for ($num=0;$num<count($fields);$num++)
            {
                  if (strlen($sql) > 7)
                  {
                        // something has been added before, so we need to add a comma as separator
                        $sql = $sql.", ";
                  }
                  // add the next field to read
                  $sql = $sql.$fields[$num];
            }
            return $sql;
      }
}

/**
 * internal use only
 *
 * build_select
 * build the SELECT part for an sql statement
 *@param $fields array of columnname(s) that will be read
 *@param $column array of available fields in column
 *@returns string
 */
function build_select2 ($fields, $column)
{
      if (count($fields) > 0)
      {
            // sql will contain the fields to read
            $sql = "SELECT ";
            for ($num=0;$num<count($fields);$num++)
            {
                  if (strlen($sql) > 7)
                  {
                        // something has been added before, so we need to add a comma as separator
                        $sql = $sql.", ";
                  }
                  // add the next field to read
                  $sql = $sql.$column[$fields[$num]];
            }
            return $sql;
      }
}

/**
 * internal use only
 *
 * this functions builds the WHERE part of the sql statement
 *@param: $required (array with pairs of columnname(s) and value(s), e.g. array('KID'=>'Admin', 'ItemID'=>$IID))
 *@returns string
 */
function build_condition ($required)
{
      if (count($required) > 0)
      {
            $sql2 = "WHERE ";
            for ($num=0;$num<count($required);$num=$num+2)
            {
                  // odd entries: fields, even entries: values
                  if (strlen($sql2) > 7)
                  {
                        // something has been added before, add an AND
                        $sql2 = $sql2." AND";
                  }
                  $sql2 = $sql2." ".$required[$num]."=";
                  if ( strlen($required[$num+1]) == 0 )
                  {
                        $sql2 = $sql2."''";
                  }
                  else
                  {
                        $sql2 = $sql2."'".pnVarPrepForStore($required[$num+1])."'";
                  }
            }
            return $sql2;
      }
}

/**
 * internal use only
 *
 * this functions builds the WHERE part of the sql statement
 *@param: $required (array with pairs of columnname(s) and value(s), e.g. array('KID'=>'Admin', 'ItemID'=>$IID))
 *@returns string
 */
function build_condition2 ($required)
{
      if (count($required) > 0)
      {
            $sql2 = "WHERE ";
            for ($num=0;$num<count($required);$num=$num+2)
            {
                  // odd entries: fields, even entries: values
                  if (strlen($sql2) > 7)
                  {
                        // something has been added before, add an AND
                        $sql2 = $sql2." AND";
                  }
                  $sql2 = $sql2." ".$required[$num]."=";
                  if ( strlen($required[$num+1]) == 0 )
                  {
                        $sql2 = $sql2."''";
                  }
                  else
                  {
                        $sql2 = $sql2."'".pnVarPrepForStore($required[$num+1])."'";
                  }
            }
            return $sql2;
      }
}

/**
 * internal use only
 *
 * this functions builds the ORDER BY part of the sql statement
 *@param: $order (array with columnname(s) of the table for sorting)
 *@returns string
 */
function build_order ($order)
{
    $sql = '';
    if (count($order) > 0)
    {
        $sql = "ORDER BY ";
        for($num=0;$num<count($order);$num++)
        {
            if (strlen($sql) > 9)
            {
                // something has been added before, add a comma as separator
                $sql = $sql.", ";
            }
            // add the next order condition
            $sql = $sql.$order[$num];
        }
    }
    return $sql;
}
/*
function build_limit ($limit)
{
      $sql = '';
      if (count($limit) = 2)
      {
            $sql = "LIMIT ".$limit[0].", ".$limit[1];
      }
      return $sql;
}
*/


/**
 * read fields from db tables
 *@param $args['table'] string (table to read from)
 *@param $args['fields'] array (fields to read)
 *@param $args['required'] array ( requirements: array('field1', $content1, 'field2', content2 ... )
 *@param $args['module'] string module name, default is zCart if not set
 *untested:
 *@param $args['order'] array ( array('field1', 'field2', ... )
 *@param $args['limit'] array ( array($startreadhere, $numberofentriestoread )
 *@returns array or false on error
 *@return array of fields in the same order as given in $args['fields']
 *
 */
function zCart_userapi_readfromDB($args)
{
    extract($args);

    // default to zCart if nothing else is mentioned
    $module = (isset($module)) ? $module : 'zCart';

    $ret = array();
    if ( isset($table) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable[$module.'_'.$table];
        $readfromtablecolumn = &$pntable[$module.'_'.$table.'_column'];
        $sql = build_select($fields)." FROM ".$readfromtable." ".build_condition($required);
        if ( isset ($order) )
        {
            $sql = $sql." ".build_order($order);
        }
        // echo "sql:$sql:<br>";
        $result = $dbconn->Execute($sql);
        // echo $sql . "<hr>";
        // check for errors
        // if ($dbconn->ErrorNo() != 0) { return false; }
        if ($dbconn->ErrorNo() != 0)
        {
            // echo 'database error in zCart_userapi_readfromDB:' . $dbconn->ErrorNo() . "/".   $dbconn->ErrorMsg();
            // pnSessionSetVar('errormsg','database error in zCart_userapi_readfromDB:' . $dbconn->ErrorNo() . "/".   $dbconn->ErrorMsg());
            return false;
        }
        // check for no rows found, and if so return
        if ($result->EOF) { return false; }
        // finally we made it here, so lets return the $result as it is
        // we build our own result array...
        if (count($result) > 0)
        {
            for($num=0;$num<count($result->fields);$num++)
            {
                $ret[$num] = $result->fields[$num];
            }
        }
        // ...because we close the result set we get
        $result->Close();
        return ($ret);
    }
    else
    {
        // echo "no table specified";
        return false;
    }
}

/**
 * read fields from db tables
 *@param $args['table'] string (table to read from)
 *@param $args['fields'] array (fields to read)
 *@param $args['required'] array ( requirements: array('field1', $content1, 'field2', content2 ... )
 *@param $args['module'] string module name, default is zCart if not set
 *untested:
 *@param $args['order'] array ( array('field1', 'field2', ... )
 *@param $args['limit'] array ( array($startreadhere, $numberofentriestoread )
 *@returns array or false on error
 *@return array of fields in the same order as given in $args['fields']
 *
 */
function zCart_userapi_readfromDB2($args)
{
    extract($args);

    // default to zCart if nothing else is mentioned
    $module = (isset($module)) ? $module : 'zCart';

    $ret = array();
    if ( isset($table) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable[$module.'_'.$table];
        $readfromtablecolumn = &$pntable[$module.'_'.$table.'_column'];
        $sql = build_select2($fields)." FROM ".$readfromtable." ".build_condition($required);
        if ( isset ($order) )
        {
            $sql = $sql." ".build_order($order);
        }
        // echo "sql:$sql:<br>";
        $result = $dbconn->Execute($sql);
        // echo $sql . "<hr>";
        // check for errors
        // if ($dbconn->ErrorNo() != 0) { return false; }
        if ($dbconn->ErrorNo() != 0)
        {
            // echo 'database error in zCart_userapi_readfromDB:' . $dbconn->ErrorNo() . "/".   $dbconn->ErrorMsg();
            // pnSessionSetVar('errormsg','database error in zCart_userapi_readfromDB:' . $dbconn->ErrorNo() . "/".   $dbconn->ErrorMsg());
            return false;
        }
        // check for no rows found, and if so return
        if ($result->EOF) { return false; }
        // finally we made it here, so lets return the $result as it is
        // we build our own result array...
        if (count($result) > 0)
        {
            for($num=0;$num<count($result->fields);$num++)
            {
                $ret[$num] = $result->fields[$num];
            }
        }
        // ...because we close the result set we get
        $result->Close();
        return ($ret);
    }
    else
    {
        // echo "no table specified";
        return false;
    }
}

/**
 *
 * reads a fieldname from the given table
 *@param args['sql'] string (working sql statement)
 *@param args['numfield'] int (number of field to return)
 *@param $args['module'] string module name, default is zCart if not set
 *@returns string or false on error
 *@return contains fieldname
 */
function zCart_userapi_readfromDBfieldname($args)
{
    extract($args);

    // default to zCart if nothing else is mentioned
    $module = (isset($module)) ? $module : 'zCart';

    $ret = array();
    if ( isset($sql) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable[$module.'_'.$table];
        $readfromtablecolumn = &$pntable[$module.'_'.$table.'_column'];
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0) { return false; }
        // check for no rows found, and if so return
        if ($result->EOF) { return false; }
        // finally we made it here, so lets return the $result as it is
        $fnum = $result->FetchField($numfield);
            // ...because we close the result set we get
            $result->Close();
            return ($fnum->name);
        }
        else
        {
            // no sql specified
            return false;
        }
}

/**
 *    *** DEPRECATED FUNCTION!!!!! ***
 *
 * return number of hits the sql statements delivers
 *@param $args['table'] string (table to read from)
 *@param $args['fields'] array (fields to read)
 *@param $args['required'] array ( requirements: array('field1', $content1, 'field2', content2 ... )
 *@param $args['module'] string module name, default is zCart if not set
 *@returns int or false on error
 *@return number of lines the sql statement delivers
 */
function zCart_userapi_readfromDBnumrows($args)
{
    die("using deprecated function pncomemrce_userapi_readfromDBnumrows()");
/*
    extract($args);
    if( !$module )
    {
        $module = 'zCart';
    }
    if ( isset($table) )
    {
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable[$module.'_'.$table];
        $readfromtablecolumn = &$pntable[$module.'_'.$table.'_column'];
        $condition = build_condition($required);
        $sql = build_select($fields)." FROM ".$readfromtable." ".$condition." ".build_order($order);
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0) { return false; }
        // check for no rows found, and if so return

        if ($result->EOF)
        {
              $recordcount = 0;
        }
        else
        {
              $recordcount = $result->RecordCount();
        }
        $result->Close();
        return $recordcount;
    }
    else
    {
          // no table specified
          return false;
    }
*/
}

/**
 * returns number of hits of preformatted sql statement
 *@param $args['sql'] string (preformatted sql statement)
 *@returns int or false on error
 *@return number of hits
 */
function zCart_userapi_readfromDBnumrowspreformat($args)
{
    extract($args);
    if ( isset($sql) )
    {
        list($dbconn) = pnDBGetConn();
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0) { return false; }
        // check for no rows found, and if so return
        if ($result->EOF)
        {
              $recordcount = 0;
        }
        else
        {
              $recordcount = $result->RecordCount(); // ($readfromtable, substr($condition, 6));
        }
        $result->Close();
        return $recordcount;
    }
    else
    {
          // no sql specified
          return false;
    }

}

/**
 *
 * read more than one line from the db
 *@param $args['table'] string (table to read from)
 *@param $args['fields'] array (fields to read)
 *@param $args['required'] array ( requirements: array('field1', $content1, 'field2', content2 ... )
 *@param $args['module'] string module name, default is zCart if not set
 *@returns array or false on error
 *@return array of array of fields, cycle it with foreach()
 */
function zCart_userapi_readmultiplefromDB($args)
{
    extract($args);

    // default to zCart if nothing else is mentioned
    $module = (isset($module)) ? $module : 'zcart';

    $ret = array();
    if ( isset($table) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable[$module.'_'.$table];
        $readfromtablecolumn = &$pntable[$module.'_'.$table.'_column'];
        $sql = build_select($fields)." FROM ".$readfromtable." ".build_condition($required)." ".build_order($order);

        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0) { return false; }
        // check for no rows found, and if so return
        if ($result->EOF) { return false; }
        // finally we made it here, so lets return the $result as it is
        // we build our own result array...
        if ( $result->RecordCount() > 0 )
        {
            for (; !$result->EOF; $result->MoveNext())
            {
                for($num=0;$num<count($result->fields);$num++)
                {
                    $temp[$num] = $result->fields[$num];
                }
                $ret[] = $temp;
            }
        }
        // ...because we close the result set we get
        $result->Close();
        return ($ret);
    }
    else
    {
        // no table specified
        return false;
    }
}

/**
 * check if user exists
 *@param $args['KID'] string (username)
 *@returns true or false
 */
function zCart_userapi_checkforuser($args)
{
    extract($args);
    unset($args);

    list($dbconn, $tablename, $tablecolumn ) = pncOpenDB('zcart_users');

    $sql = "SELECT $tablecolumn[UserName]
            FROM $tablename
	        WHERE $tablecolumn[UserName]='".pnVarPrepForStore($KID)."'";
    $result = $dbconn->Execute($sql);
    // check for errors or no rows found, and if so return false
    if (($dbconn->ErrorNo() != 0) || ($result->EOF) ) {
        pncCloseDB($result);
        return false;
    }
    list($readkid) = $result->fields;
    pncCloseDB($result);
    return ($readkid==$KID);
}

/**
 * read one line fro db with preformatted sql statement
 *@param $args['sql'] string (working sql statement)
 *@returns array
 *@return array of fields as requested in the sql statement
 */
function zCart_userapi_readfromDBpreformat($args)
{
      extract($args);
      $ret = array();
      if ( isset($sql) )
      {
            list($dbconn) = pnDBGetConn();
            $result = $dbconn->Execute($sql);
            // check for errors
            if ($dbconn->ErrorNo() != 0)
            {
            	return false;
            }
            // check for no rows found, and if so return
            if ($result->EOF) { return false; }
            // finally we made it here, so lets return the $result
            for (; !$result->EOF; $result->MoveNext())
            {
                  for($num=0;$num<count($result->fields);$num++)
                  {
                      $temp[$num] = $result->fields[$num];
                  }
                  $ret[] = $temp;
            }
            $result->Close();
            return ($ret);
      }
      else
      {
            // no sql specified
            return false;
      }
}

/**
 * execute preformatted sql statement, e.g. for updating
 *@param $args['sql'] string (working sql statement)
 *@returns true on success or false
 */
function zCart_userapi_executesqlDB($args)
{
    extract($args);
    if ( isset($sql) ) {
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0) {
            // return $dbconn->ErrorNo();
            return false;
        }
        $result->Close();
        return true;
    } else {
        // no sql specified
        return false;
    }
}

/**
 * insert something into the db with an preformatted sql statement and return the
 * new id
 *@param $args['sql'] string (working sql statement)
 *@param $args['table'] string (tablename)
 *@param $args['indexfield'] string (name of the autoincrement field)
 *@returns int or false on error
 */
function zCart_userapi_insertintoDB($args)
{
    extract($args);
    if ( isset($table) AND isset($sql) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $writetotable = $pntable['zcart_'.$table];
        $writetotablecolumn = &$pntable['zcart_'.$table.'_column'];
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0)
        {
              return false;
        }
        else
        {
            $newid = 0;
            if (isset($idfield) )
            {
                $newid = $dbconn->PO_Insert_ID($writetotable, $idfield);
            }
        }
        $result->Close();
        return $newid;
    }
    else
    {
        // neither table nor sql specified
        return false;
    }
}

/**
 *gethighidfromDB
 * return highest value of given autoincrement field
 *@param $args['table'] string
 *@param $args['indexfield'] string (must be a autoincrement field !!)
 *@returns highest id in the table or false on error
 */
function zCart_userapi_gethighidfromDB($args)
{
    extract($args);
    if ( isset($table) )
    {
        pnModDBInfoLoad('zCart');
        list($dbconn) = pnDBGetConn();
        $pntable = pnDBGetTables();
        $readfromtable = $pntable['zcart_'.$table];
        $readfromtablecolumn = &$pntable['zcart_'.$table.'_column'];
        $sql = "SELECT $indexfield FROM $readfromtable ORDER BY $indexfield DESC LIMIT 2";
        $result = $dbconn->Execute($sql);
        // check for errors
        if ($dbconn->ErrorNo() != 0)
        {
            return false;
        }
        $highid = $result->fields[0];
        $result->Close();
        return $highid;
    }
    else
    {
        // no table specified
        return false;
    }
}

/**
 * get the name of the image that is located on the server
 * we need this function because we have more filetypes available and
 * we need to know which filename we have to use.
 * @param $args['ItemSKU']  integer the SKU of the corresponding item
 * @param $args['thumbnail'] bool optional To indicate if the item is a thumbnail or not. If the parameter is not given we assume that it is a regular image.
 * @param $args['imagefolder'] string optional the targetfolder for the images. product_images is used, if this parameter is empty.
 * @return full name (String) if everything is ok, otherwise false
 */
function zCart_userapi_getImageName($args)
{
    $basename="modules/zCart/";
    if(isset($args['imagefolder']))
    {
        $basename .= $args['imagefolder']."/".$args['ItemSKU'];
    }
    else
    {
        $basename .= "product_images/".$args['ItemSKU'];
    }
    $basename1 = "";
    if($args['thumbnail']===true)
    {
	$basename1 = $basename . "thmb";
        $basename .= "tn";
    }
    $basename .= ".";
    $basename1 .= ".";
    //OK, let's go through all available filetypes:
    $filetypes=array( '1'=>'jpg', //Order is important, the right order makes the function faster
                      '2'=>'gif',
                      '3'=>'png',
                      '4'=>'jpeg',
                      '5'=>'bmp');

    foreach($filetypes as $row)
    {
        if (file_exists($basename.$row))
        {
            return ($basename.$row);
        }
	if (file_exists($basename1.$row))
	{
		return($basename1.$row);
	}
    }
    //nothing found
    return false;
}

/**
 * reads a template from the database by ID
 * if necessary, external file will be loaded
 * @param $args['TemplateID'] int valid TemplateID to read
 * @param $args['DescOnly'] boolean if set to true, we will return the template description instead of the contents
 *                                  default is false
 * @returns string filename of the template or false on error
 */
function zCart_userapi_GetTemplateByID ($args)
{
    extract ($args);
    if( isset($TemplateID) && is_numeric($TemplateID) )
    {
        list($dbconn, $tablename, $tablecolumn ) = pncOpenDB('zcart_templates');
        $sql = "SELECT $tablecolumn[template_file],
                       $tablecolumn[template_description]
                FROM $tablename
	            WHERE $tablecolumn[template_id]=".(int)pnVarPrepForStore($TemplateID)." ";
        $result = $dbconn->Execute($sql);
        // check for errors or no rows found, and if so return false
        if (($dbconn->ErrorNo() != 0) || ($result->EOF) ) { return false; }
        list($template, $description) = $result->fields;
        pncCloseDB($result);
        if(empty($template))
        {
            return pnVarPrepForDisplay(_ERRORNOTEMPLATEDEFINED."(3-ID:$TemplateID)");
        }
        if( $DescOnly === true)
        {
            return $description;
        }
        else
        {
            return $template;
        }
    }
    else
    {
        return false;
    }
}

/**
 * get the valid vat by searching the category tree if necessary
 *@param $args['CID'] CategoryID
 *@param $args['ItemID'] int
 *@returns double valid vat
 */
function zCart_userapi_GetVATbyItemID ($args)
{
    extract($args);
    while ($CID)
    {
        list($VATID, $CID) = zCart_userapi_readfromDB(array('table' => 'category',
                                                                 'fields' => array('VATID', 'CatParent'),
                                                                 'required' => array('CategoryID', $CID)));
        if ($VATID != 0 )
        {
            // CatParent has a valid VATID so we use this
            return pnModGetVar( 'zCart', 'VATID'.$VATID );
        }
    }
    // we search all CatParents without finding a valid VATID,
    // this should not happen, now we have a vat of 0 % !!
    return 0;
}

/**
 * get the VAT percentage for the given ID
 * a possible result is 16, this represents 16%, so you have to use the formula:
 * endprice=price*(1+VAT/100.0)
 * or includedVAT=price*VAT/100.0
 * @param $args['VATID'] int 1..9
 * @returns int >= 0
 * @return int the VAT percentage for the given ID
 */
function zCart_userapi_getVAT($args)
{
    if(($args['VATID']<1)or($args['VATID']>9))return false;
    $vat = double;
    $vat = pnModGetVar('zCart','VATID'.$args['VATID']);
    return $vat;
}

/**
 * Returns all cartitems with all necessary informations
 * when you provide a BPM and/or BSM these informations are also included
 * @param $args['KID'] int CustomerID
 * @param $args['BPM'] string optional paymethod
 * @param $args['BSM'] string optional shippingmethod
 * @returns array or false when cart is empty
 *@return array, all items, sums, ... All you need to know about the cart
 *@return ['CartItems'] Array, All items in the cart
 *@return ['CartItems']['ItemID'] The itemID
 *@return ['CartItems']['CartItemsID'] The ID inside the cart
 *@return ['CartItems']['ItemSKU'] The ItemSKU
 *@return ['CartItems']['ItemName'] the descriptive name of this item
 *@return ['CartItems']['ItemCost'] The itemcost without VAT
 *@return ['CartItems']['ItemCostLong'] The itemcost with VAT
 *@return ['CartItems']['ItemCostTotal'] The itemcost with VAT * quantity
 *@return ['CartItems']['ItemVAT'] Array, the VAT informations for this Item
 *@return ['CartItems']['ItemVAT']['VATID'] the VATID for this Item
 *@return ['CartItems']['ItemVAT']['VAT'] the VAT percentage for this Item for example 16 for 16%
 *@return ['CartItems']['Weight'] The item weight
 *@return ['CartItems']['ItemQuantity'] quantity in the cart
 *@return ['CartItems']['IgnoreQuantity'] whether the
 *@return ['CartItems']['QuantityOrdered'] the ordered quantity (but what is this?)
 *@return ['CartItems']['Category'] The Categoryname of this item
 *@return ['CartItems']['CategoryID'] The CategoryID of this item
 *@return ['CartItems']['TaxExempt'] 'on' is not tax on this item
 *@return ['WeightTotal'] The total weight of the cart
 *@return ['ItemsTotal'] the sum of all items
 *@return ['SubTotal'] the sum of all itemcosts including VAT
 *@return ['VATList'] Array, the sum of all different VAT's
 *@return ['VATList']['<VATID>'] the sum of the VAT of all items that have the VATID=<VATID>
 *@return ['FinalModTotal'] The sum of all FinalMods
 *@return ['FinalMod'] Array, The list with all FinalModnames and their amount
 *@return ['FinalMod']['Name'] Name of the Finalmod, handling or Tax for example
 *@return ['FinalMod']['Amount'] The finalmod cost
 *@return ['ShippingTotal'] optional The shipping cost
 *@return ['PaymethodTotal'] optional The paymethod costs
 */
function zCart_userapi_getCart($args)
{
    extract($args);
    if (!pnModAPILoad('zCart', 'user'))
    {
        return showerrorpage("unable to load pnuserapi", __FILE__, __LINE__);
    }
    //get the cart items
    $result = pnModAPIFunc( 'zCart', 'user', 'readmultiplefromDB',
                            array( 'table' => 'cartitems',
                                   'fields' => array('ItemID', 'ItemQuantity', 'CartItemsID'),
                                   'required' => array('UserID', $KID)));
    if ( $result <> false )//empty cart?
    {
        $Cart=array();
        $CartItems=array();
        $VATList=array();
        $ItemCost= 0.1;
        foreach($result as $resultline)
        {
            list($ItemID, $ItemQuantity, $CartItemsID) = $resultline; // new !!
            $rawItem = pnModAPIFunc( 'zCart', 'user', 'getItem', array( 'ItemID' => $ItemID ) );
            if($rawItem===false){//strange thing happened, we have a item in the cart that is not in our Database
                $rawItem['Weight']=0;
                $rawItem['SKU']=_PNC_ITEM." $ItemID  "._PNC_NOTAVAILABLE;
                $rawItem['Name']=_PNC_ERRORITEMNOTINDATABASE;
                $rawItem['Desc']=_PNC_ITEM." $ItemID :"._PNC_ERRORITEMNOTINDATABASE;
                $rawItem['Cost']=0;
                $rawItem['CostLong']=0;
                $rawItem['Vat']=0;
                $rawItem['VatAmount']=0;
                $rawItem['Quantity']=0;
                $rawItem['IgnoreQuantity']=0;
                $rawItem['OrderedQuantity']=0;
                $rawItem['Category']='';
                $rawItem['CategoryID']='';
                $rawItem['TaxExempt']='';
            }
            //We put this here in the array to display it later.
            //We have to create a list where the sum of the VAT is in relation to the VATID when VAT is >0
            //16% = 3,44 EUR, 7%= 1,00 EUR, ...
            if( isset( $rawItem['Vat'] ) && ( $rawItem['VatAmount'] > 0 ) )
            {
                $VATList[ strval( $rawItem['Vat'] ) ]+= $rawItem['VatAmount'] * $ItemQuantity;
            }
            $WeightTotal 	+= 	( $ItemQuantity * $rawItem['Weight'] );
            $ItemsTotal 	+=	$ItemQuantity;//itemstotal is the number of items in the cart
            $ItemTotal       	= 	( $ItemQuantity * $rawItem['CostLong'] );
            $SubTotal 		= 	$SubTotal + $ItemTotal;

            //This is all data we need for these items.
            //When we add custom properties later we have to put them here in too
            array_push( $CartItems,
                    array('ItemID'          => $ItemID,
                          'CartItemsID'       => $CartItemsID,
                          'ItemSKU'           => $rawItem['SKU'],
                          'ItemName'          => $rawItem['Name'],
                          'ItemDescription'   => $rawItem['Desc'],
                          'ItemCost'          => $rawItem['Cost'],
                          'ItemCostLong'      => $rawItem['CostLong'] ,
                          'ItemCostTotal'     => $ItemTotal,
                          'ItemVAT'           => $rawItem['Vat'],
                          'Weight'            => $rawItem['Weight'],
                          'ItemQuantity'      => $ItemQuantity,
                          'ItemQuantityOnHand'=> $rawItem['Quantity'],
                          'IgnoreQuantity'    => $rawItem['IgnoreQuantity'],
                          'QuantityOrdered'   => $rawItem['OrderedQuantity'],
                          'Category'          => $rawItem['Category'],
                          'CategoryID'          => $rawItem['CategoryID'],
                          'TaxExempt'         => $rawItem['TaxExempt'] ) );
        }

/*######################################################
# I hope this way is right.
# I assume:
# - you don't pay finalmod costs for shipping and paying
# - the finalmod costs increase the amount you have to pay for shipping (when the money is taken for calculation there)
# - you have to pay "Paymethodcost" for shipping and finalMod
# (because it depends on the amount you have to pay and shipping may increase this sum belongs to it)
#######################################################*/

//Calculate shipping costs
        //the following 2 steps are important for generic shippingmethods
        $SM=$BSM;
        if(ereg("smgeneric", $BSM))
        {
        	$BSM='smgeneric';
        }
        if(ereg("smups", $BSM))
        {
        	$BSM='smups';
        }
        if (isset($BSM)&&pnModAPILoad('zCart', $BSM))
        {
            $ShippingTotal =pnModAPIFunc( 'zCart', $BSM, 'getShippingTotal',
                                array('ShippingMethod'=>$SM,'WeightTotal' => $WeightTotal, 'ItemsTotal'=>$ItemsTotal, 'SubTotal'=>($SubTotal+$finalModTotal)));
            $ShippingFootermsg=pnModAPIFunc ('zCart', $BSM, 'footermsg', array ('ShippingMethod'=>$SM,'KID' => $KID));
        }
//Calculate Paymethod costs
    //the following 2 steps are important for generic paymethods
    $PM=$BPM;
    if(ereg("pmgeneric", $BPM))
    {
        $BPM='pmgeneric';
    }
        if (isset($BPM)&&pnModAPILoad('zCart', $BPM))
        {
            $PaymethodTotal =pnModAPIFunc( 'zCart', $BPM, 'getPaymethodTotal',
                                array('PayMethod'=>$PM,'SubTotal'=>($SubTotal+$ShippingTotal+$finalModTotal)));//consider all costs
            $PaymethodFootermsg=pnModAPIFunc ('zCart', $BPM, 'footermsg', array ('PayMethod'=>$PM,'KID' => $KID));
        }
        // finalmod replacement : order modifiers
        // array to hold name and amounts
        $ordermodifierarray = array();
        // get the sequence
        $ordermodsequence = pnModGetVar( 'zCart', 'OrderModifierSequence' );
        if( isset($ordermodsequence) )
        {
            $ordermodsequence = unserialize( $ordermodsequence );
            if( is_array($ordermodsequence ) )
            {
                if( count($ordermodsequence) > 0 )
                {
                    // we have atleat one ordermodifier to take care about
                    // cycle the modifier array
                    foreach( $ordermodsequence as $modifiername )
                    {
                        // check if modifier is activated
                        if( pnModGetVar( 'zCart', $modifiername ) == 'on' )
                        {
                            // modifier is acive
                            if( pnModAPILoad( 'zCart', $modifiername ) )
                            {
                                // api loaded
                                $modifierinfo   = pnModAPIFunc( 'zCart', $modifiername, 'info' );
                                $modifierfooter = pnModAPIFunc( 'zCart', $modifiername, 'FooterMsg' );
                                $modifieramount = pnModAPIFunc( 'zCart', $modifiername, 'checkout',
                                                                array( 'CartItems'      => $CartItems,
                                                                       'WeightTotal'    => $WeightTotal,
                                                                       'ItemsTotal'     => $ItemsTotal,
                                                                       'SubTotal'       => $SubTotal,
                                                                       'ShippingTotal'  => $ShippingTotal,
                                                                       'PaymethodTotal' => $PaymethodTotal,
                                                                       'OrderModifiers' => $ordermodifierarray ) );
                                $ordermodifiertotal += $modifieramount;
                                array_push( $ordermodifierarray, array( 'Name'   => $modifiername,
                                                                        'Info'   => $modifierinfo,
                                                                        'Footer' => $modifierfooter,
                                                                        'Amount' => $modifieramount ) );
                            }
                        }
                    }
                }
            }
        }
//Done with the calculation
//Now put everything together in the big array.
        $Cart['CartItems'] = $CartItems;//All items in the cart
        $Cart['WeightTotal'] = $WeightTotal;//The total weight of the cart
        $Cart['ItemsTotal'] = $ItemsTotal; //the sum of all items
        $Cart['SubTotal'] = $SubTotal; //the sum of all itemcosts including VAT
        $Cart['VATList'] = $VATList; //the sum of all different VAT's
        $Cart['PaymethodFootermsg'] = $PaymethodFootermsg; //footermessage generated by the selected paymethod
        $Cart['ShippingFootermsg'] = $ShippingFootermsg; //footermessage generated by the selected shippingmethod
        // old style : $Cart['FinalModTotal'] = $finalModTotal;//The sum of all FinalMods
        $Cart['OrderModifierTotal'] = $ordermodifiertotal;//The sum of all FinalMods
        if(isset($BSM))$Cart['ShippingTotal'] = $ShippingTotal;//The shipping cost
        if(isset($BPM))$Cart['PaymethodTotal'] = $PaymethodTotal; //The paymethod costs
        // old style : $Cart['FinalMod'] = $finalMod; //Array, The list with all FinalModnames and their amount
        $Cart['OrderModifier'] = $ordermodifierarray; //Array, The list with all FinalModnames and their amount
        // old style : $Cart['Total'] = $SubTotal + $ShippingTotal + $PaymethodTotal +$finalModTotal ; //the total sum of all costs including VAT
        $Cart['Total'] = $SubTotal + $ShippingTotal + $PaymethodTotal +$ordermodifiertotal ; //the total sum of all costs including VAT
        return $Cart;
    }
    return false;
}

/**
 * get the VAT percentage and VATID for the given category
 * a possible result is 16, this represents 16%, so you have to use the formula:
 * endprice=price*(1+VAT/100.0)
 * or includedVAT=price*VAT/100.0
 * @param $args['CategoryID'] The CategoryID for the query
 * @returns array (or false on error)
 * @return  'VATID' [1..9]
 * @return  'VAT' int >= 0
 */
function zCart_userapi_getCategoryVAT($args)
{
    $categoryResult = zCart_userapi_readfromDB(array('table' => 'category',
                                  'fields' => array ('VATID','CatParent'),
                                  'required' => array('CategoryID', $args['CategoryID'])));

    if($categoryResult==false)return false;
    list($VATID,$CategoryParent)=$categoryResult;
    if($VATID==0)
    {
        //We have to look for a parent VATID
        if($CategoryParent)
        {
            return  zCart_userapi_getCategoryVAT(array('CategoryID'=>$CategoryParent));
        }
        else
        {
            //No VAT set, so we assume the VAT is 0%
            return  array('VATID'=>0,  'VAT'=>0);
        }
    }
    else
    {
        //OK, this is simple just return the VAT
        $vat = (double) pnModAPIFunc( 'zCart', 'user', 'getVAT', array( 'VATID' => $VATID ) );
        return array('VATID'=>$VATID,'VAT'=> $vat);
    }
}

/**
 * get just the name of a category. This function is normally used in permission checks
 * this is just a shortcut function to simplify the checks
 * @param $args['CategoryID'] The CategoryID for the query
 * @return String the name of the category
 */
function zCart_userapi_GetCategoryName($args)
{
   //list is necessary here! Don't remove it!
    list($categoryResult) = zCart_userapi_readfromDB(array('table' => 'category',
                                  'fields' => array ('Category'),
                                  'required' => array('CategoryID', $args['CategoryID'])));
    if( is_serialized( $categoryResult ) == false )
    {
        return $categoryResult;
    }
    $c_hack = unserialize( $categoryResult );
    return $c_hack['name'];
}

/**
 * This function removes all lines in the array that have not at least the given permission.
 * The default values fit to filter the itemlist for category data
 * @param $args['List'] The list of items to filter
 * @param $args['Component'] The component description, default is 'zCart::category'
 * @param $args['1stPart'] the name of the field for the first instance field, default is 'Category'
 * @param $args['2ndPart'] the name of the field for the second instance field, default is 'CategoryID'
 * @param $args['Level'] optional, The permission level that is checked for, default is overview
 * @return Array the filtered array
 */
function zCart_userapi_PermissionFilterArray($args)
{
    $List=$args['List'];
    if(!$args['Component']) $args['Component']='zCart::category';
    if(!$args['1stPart']) $args['1stPart']='Category';
    if(!$args['2ndPart']) $args['2stPart']='CategoryID';
    if(!$args['Level']) $args['Level']=ACCESS_OVERVIEW;
    foreach($List as $key=>$line)
    {
        if(!pnSecAuthAction(0, $args['Component'], $line[$args['1stPart']]."::".$line[$args['2ndPart']], $args['Level']))
        {
//         echo $line[$args['1stPart']]."::".$line[$args['2ndPart']]." FAIL<br>";
          unset($List[$key]);
        }
//        else echo $line[$args['1stPart']]."::".$line[$args['2ndPart']]." pass<br>";
    }
    return $List;
}

/**
 * get the VAT percentage and VATID for the given product
 * a possible result is 16, this represents 16%, so you have to use the formula:
 * endprice=price*(1+VAT/100.0)
 * or includedVAT=price*VAT/100.0
 * @param $args['ItemID'] The ItemID for the query
 * @returns array (or false on error)
 * @return  'VATID' [1..9]
 * @return  'VAT' int >= 0
 */
function zCart_userapi_getItemVAT($args)
{
    $itemResult = zCart_userapi_readfromDB(array('table' => 'items',
                                  'fields' => array ('VATID','Category'),
                                  'required' => array('ItemID', $args['ItemID'])));
    if($itemResult==false)return false;
    list($VATID,$CategoryID)=$itemResult;
    if($VATID==0)
    {
        //We have to look for a parent VATID
        return  zCart_userapi_getCategoryVAT(array('CategoryID'=>$CategoryID));
    }
    else
    {
        //OK, this is simple just return the VAT
        return array('VATID'=>$VATID,'VAT'=>zCart_userapi_getVAT(array('VATID'=>$VATID)));
    }
}

/**
 * Parses the form data for the calculation functions and returns the config array for it.
 * all parameters are included in the returned array as well
 * @param $args['PMCalcFunc'] the name of the calculation function
 * @param $args['name'] optional, this is used as offset (we need this when we gather generic data)
 * @returns array all the data provided in $args + the additional data for this function gathered with pnVarCleanfromImput
 * @return  'VATID' [1..9]
 * @return  'VAT' int >= 0
 */
function zCart_userapi_gatherPMCalcData($args)
{
//	if(isset($args['name']))$offset="_".$args['name'];
    if(isset($args['name']))$offset=$args['name'];
    //no fee when ordercost is higher than x
    if(pnVarCleanFromInput('PMCFreeFrom'.$offset)=='Yes')
    {
        $args['PMCFreeFrom'] = 'Yes';
        $args['PMCFreeFromValue'] = pnVarCleanFromInput('PMCFreeFromValue'.$offset);
    }
    if($args['PMCalcFunc']=='PMCFlat')
    {
        $args['PMCFlatPrice'] = pnVarCleanFromInput('PMCFlatPrice'.$offset);
    }
    else if($args['PMCalcFunc']=='PMCPercent')
    {
        $args['PMCPercentMinPrice'] = pnVarCleanFromInput('PMCPercentMinPrice'.$offset);
        $args['PMCPercentMaxPrice'] = pnVarCleanFromInput('PMCPercentMaxPrice'.$offset);
        $args['PMCPercentage'] = pnVarCleanFromInput('PMCPercentage'.$offset);
    }
    return $args;
}


/**
 * returns value, based on the given pmcalcfunc
 * @param $args['Value'] value of the current order
 * @param $args['PMCalcFunc'] string, the current PM-fee calculation function
 * @param $args[...] data for this calc func
 * @returns string
 */
function zCart_userapi_getPMCalcValue($args)
{
    if (!pnModAPILoad( 'zCart', 'user'))
    {
        return showerrorpage("unable to load pnuserapi", __FILE__, __LINE__);
    }
//first do general calculations
    if(($args['PMCFreeFrom']=='Yes')&&($args['PMCFreeFromValue']<=$args['Value'])) return 0;
//then bypass the values to the calcfuncs
    return pnModAPIFunc( 'zCart','user',$args['PMCalcFunc']."Calc",$args);
}

/**
 * returns the value of the flat-fee
 * @param $args['Value'] value of the current order
 * @param $args['PMCFlatPrice'] the price
 * @returns string
 */
function zCart_userapi_PMCFlatCalc($args)
{
    return $args['PMCFlatPrice'];
}

/**
 * returns the value of the Percent-fee
 * @param $args['Value'] value of the current order
 * @param $args['PMCPercentMinPrice'] the minimum price
 * @param $args['PMCPercentMaxPrice'] the maximum price
 * @param $args['PMCPercentage'] the percentage for the fee. for example '16' for 16%
 * @return double
 */
function zCart_userapi_PMCPercentCalc($args)
{
    //calculate value
    $value=$args['Value']*((1.*$args['PMCPercentage'])/100.0);
    //less than minimum?
    if($value<$args['PMCPercentMinPrice']) $value=$args['PMCPercentMinPrice'];
    //is there a max price?
    if($args['PMCPercentMaxPrice']>0){
    //more than max price?
    if($args['PMCPercentMaxPrice']<$value)$value=$args['PMCPercentMaxPrice'];
     }
    return $value;
}


/**
 * reads the properties from the database for the given object_id and the given type
 * @param $args['showhidden'] bool optional show hidden properties too, default is true
 * @param $args['object_id'] int object id to read
 * @param $args['object_type'] int object type to read, default is 0 (item)
 * @returns array
 */
function zCart_userapi_GetPropertiesByID ($args)
{

    $object_type=PNC_ITEMPROP;
    $showhidden=true;
    extract ($args);
    if( isset($object_id) && is_numeric($object_id) && isset($object_type) && is_numeric($object_type) )
    {

		list($dbconn, $pntable, $tablecolumn) = pncOpenDB();
        $propertiestable = $pntable['zcart_properties'];
        $propertiescolumn = &$pntable['zcart_properties_column'];
        $propertiesdatatable = $pntable['zcart_propertiesdata'];
        $propertiesdatacolumn = &$pntable['zcart_propertiesdata_column'];
        $sql = "SELECT $propertiescolumn[property_id] as property_id,
                    $propertiescolumn[scheme_id] as scheme_id,
                    $propertiescolumn[timestamp] as timestamp,
                    $propertiescolumn[name] as name,
                    $propertiescolumn[type] as type,
                    $propertiescolumn[hidden] as hidden,
                    $propertiescolumn[config] as config,
                    $propertiescolumn[sortorder] as sortorder,
                    $propertiesdatacolumn[propertydata_id] as propertydata_id,
                    $propertiesdatacolumn[object_id] as object_id,
                    $propertiesdatacolumn[object_type] as object_type,
                    $propertiesdatacolumn[integerfield] as integerfield,
                    $propertiesdatacolumn[stringfield] as stringfield,
                    $propertiesdatacolumn[longtextfield] as longtextfield
                FROM $propertiestable, $propertiesdatatable
	            WHERE $propertiescolumn[property_id]=$propertiesdatacolumn[property_id]
                 AND $propertiesdatacolumn[object_type]=".(int)pnVarPrepForStore($object_type)."
                 AND $propertiesdatacolumn[object_id]=".(int)pnVarPrepForStore($object_id);
         if(!$showhidden) $sql.=" AND $propertiescolumn[hidden]='0'";
         $sql.=" ORDER BY $propertiescolumn[sortorder]";
		 $result = $dbconn->Execute($sql);
        // check for errors or no rows found, and if so return false
        if ($dbconn->ErrorNo() != 0) {
          pnSessionSetVar('errormsg', _GETFAILED . " - ".__FILE__.": ".__LINE__." \n'" . $dbconn->ErrorMsg() . "' <br>");
          return false;
        }
        $props=array();
        for (;$result->EOF == false;$result->MoveNext()) {
          $prop = $result->GetRowAssoc(false);
          //unserialize if necessary
          $unserialized=unserialize($prop['config']);
          if(is_array($unserialized))$prop['config']=$unserialized;

          $props[$prop['propertydata_id']]=$prop;
        }
        $result->Close();
        return $props;
    }
    //When we get here, then something must went wrong
    pnSessionSetVar('errormsg', _GETFAILED . " - ".__FILE__.": ".__LINE__." \n'PARAM_ERR!' <br>");
    return false;
}




/**
 * getItem
 * reads the given item from the database and calculates missing values
 *@param $args['ItemSKU'] string items sku
 *@param $args['ItemID'] int items id
 *@param $args['CID'] int category id
 *@param $args['showhidden'] shows hidden dynamic properties, optional, default is false
 * You must specify either ItemID or ItemSKU, both will work. When giving both values as parameter
 * we look first for the ID, then for the SKU
 *@returns array or false on error
 *@return Item['ID']
 *@return Item['SKU']
 *@return Item['Name']
 *@return Item['Desc']
 *@return Item['Cost']
 *@return Item['Vat'] the percentage value
 *@return Item['VatAmount']
 *@return Item['CostLong']
 *@return Item['Category']
 *@return Item['CategoryID']
 *@return Item['IgnoreQuantity']
 *@return Item['Quantity']
 *@return Item['OrderedQuantity']
 *@return Item['Weight']
 *@return Item['propertiesdata']
 *@return Item['Scheme_ID']
 *@return Item['Supplier_ID']
 *@return Item['TaxExempt']
 */
function zCart_userapi_getItem( $args )
{
    $showhidden=false;
    extract( $args );
    if( ( isset( $ItemSKU ) ) or ( isset( $ItemID ) ) )
    {
        $Item = array();
        $Item['ID'] 		= 0;
        $Item['SKU']		= '';
        $Item['Name']		= '';
        $Item['Desc'] 		= '';
        $Item['Cost']		= double;
        $Item['Vat'] 		= double;
        $Item['VatID']      = 0;
        $Item['VatAmount'] 	= double;
        $Item['CostLong']  	= double;
        $Item['Category']       = '';
        $Item['CategoryID']       = 0;
        $Item['IgnoreQuantity'] = int;
        $Item['Quantity'] 	= int;
        $Item['OrderedQuantity']= int;
        $Item['Weight']		= double;
        $Item['TaxExempt']  = '';
        $Item['Scheme_ID']  = -1;
	$Item['Supplier_ID'] = 0;

        if( $ItemID == -1 )
        {
            // creat new item
            $Item['ID'] 		= -1;
            $Item['SKU']		= '';
            $Item['Name']		= '';
            $Item['Desc'] 		= '';
            $Item['Cost']		= 0.0;
            $Item['Vat'] 		= 0.0;
            $Item['VatID']      = 0;
            $Item['VatAmount'] 	= 0.0;
            $Item['CostLong']  	= 0.0;
            $Item['Category']       = '';
            $Item['CategoryID']       = 0;
            $Item['IgnoreQuantity'] = 0;
            $Item['IgnoreQuantityHTML'] = '';
            $Item['Quantity'] 	= 0.0;
            $Item['OrderedQuantity']= 0.0;
            $Item['Weight']		= 0.0;
            $Item['TaxExempt']	= '';
            $Item['TaxExemptHTML']	= '';
            $Item['Image']	= '';
            $Item['ImageTN']	= '';
            $Item['Scheme_ID']  = -1; //none
            return $Item;
        }

        list($dbconn, $pntables) = pncOpenDB();
        $itemtable = $pntables['zcart_items'];
        $categorytable = $pntables['zcart_category'];

        $sql = "SELECT i.ItemID,
                       i.scheme_id,
                       i.ItemSKU,
                       i.ItemName,
                       i.ItemDescription,
                       i.ItemCost,
                       i.VATID,
                       i.Category,
                       i.IgnoreQuantity,
                       i.ItemQuantity,
                       i.QuantityOrdered,
                       i.Weight,
                       i.TaxExempt,
		       i.supplier_id,
                       c.Category,
                       c.CatParent,
                       c.CatInvisible,
                       c.CatIntroTemplateID,
                       c.ItemListTemplateID,
                       c.ItemViewTemplateID
                FROM $itemtable AS i,
                     $categorytable AS c
	            WHERE ";
        if( isset( $ItemID ) )
        {
            $sql .= "i.ItemID= '" . (int)pnVarPrepForStore($ItemID)."'";
        }
        else
        {
            $sql .= "i.ItemSKU='" . pnVarPrepForStore($ItemSKU)."'";
        }
        $sql .= " AND c.CategoryID=i.Category";
        // execute the sql command
        $result = pncExecuteSQL($dbconn, $sql, __FILE__, __LINE__);
        list( $Item['ID'],
              $Item['Scheme_ID'],
              $Item['SKU'],
              $Item['Name'],
              $Item['Desc'],
              $Cost,
              $Item['VatID'],
              $Item['CategoryID'],
              $Item['IgnoreQuantity'],
              $Item['Quantity'],
              $Item['OrderedQuantity'],
              $Item['Weight'],
              $Item['TaxExempt'],
	      $Item['Supplier_ID'],
              $Item['Category'],
              $Item['CatParent'],
              $Item['CatInvisible'],
              $Item['CatIntroTemplateID'],
              $Item['ItemListTemplateID'],
              $Item['ItemViewTemplateID'] ) = $result->fields;
        pncCloseDB($result);
        $Cost=number_format($Cost, 3, '.', '');
        $Item['Cost'] =$Cost;// $val[0] + ( $val[1] / 100 );
        $Item['Weight']=number_format($Item['Weight'], 3, '.', '');
        // Category may be serialized
        if(is_serialized($Item['Category']) == true) {
            $c_hack = unserialize($Item['Category']);
            $Item['Category'] = $c_hack['name'];
        }

        if (!(pnSecAuthAction(0, 'zCart::item', $Item['SKU'].'::'.$Item['ID'], ACCESS_OVERVIEW)
         &&pnSecAuthAction(0, 'zCart::category', $Item['Category'].'::'.$Item['CategoryID'], ACCESS_OVERVIEW)))
          {
            return showerrorpage(_PNC_NOAUTH, __FILE__, __LINE__);
          }
        $Item['PropertiesData']=array();
        //Fetch properties for this item and call their load function
        $props=pnModAPIFunc( 'zCart', 'user', 'getPropertiesByID', array('showhidden' => $showhidden, 'object_id' => $Item['ID'],'object_type'=> PNC_ITEMPROP ) );
        if(!empty($props)){
            foreach($props as $prop)
            {
              if (!pnModAPILoad ('zCart', $prop['type']))
              {
                  return showerrorpage( ""._PNC_LOADMODULEAPIFAILED.": PR $prop[type]", __FILE__, __LINE__ );
              }
              $Item=pnModAPIFunc( 'zCart', $prop['type'], 'load', array('object'=>$Item,'property'=>$prop));
    //We should add a switch here if we are in edit mode. We can remove the longextfield here for example
              $Item['PropertiesData'][]=$prop;

            }
        }

        // make sure that we have no ,/. problems in the numberformat
        if( $Item['VatID'] != 0 )
        {
            // VAT from Item
            $val = split ( "[.,]", pnModGetVar( 'zCart', 'VATID'.$Item['VatID'] ) );
            $Item['TrueVatID'] = true;
        }
        else
        {
            // VAT not defined for Item, use VAT from hierarchy of categories instead.
            $val = split ( "[.,]", pnModAPIFunc( 'zCart', 'user', 'GetVATbyItemID',
                                    array( 'ItemID' => $Item['ID'],
                                         'CID' => $Item['CategoryID'] ) ) );
            $Item['TrueVatID'] = false;
        }
        $Item['Vat'] = $val[0] + ( $val[1] / 10 );
//        $val = split ( "[.,]", $Cost );
        if (pnModGetVar('zCart', 'VatIncluded') != 'on')
        {
            // price doesn't contain vat, like in the US
            $Item['VatAmount']      = round( ( ( $Item['Cost'] * $Item['Vat'] ) / 100), 2 );
            $Item['CostLong']       = $Item['Cost'] + $Item['VatAmount'];
        }
        else
        {
            // price already contains the vat, like for end user shops in Germany
            $Item['VatAmount'] = $Item['Cost'] / (100 + $Item['Vat']) * ($Item['Vat']);
            $Item['CostLong'] = $Item['Cost'];
            $Item['Cost'] = $Item['CostLong'] - $Item['VatAmount'];
        }
        if( $Item['TaxExempt'] == 'on' )
        {
            $Item['TaxExemptHTML'] = 'checked';
        }
        if( $Item['IgnoreQuantity'] == 'on' )
        {
            $Item['IgnoreQuantityHTML'] = 'checked';
        }
        $Item['Image'] = pnModAPIFunc( 'zCart', 'user', 'getImageName', array( 'ItemSKU' => $Item['SKU'] ) );
        $Item['ImageTN'] = pnModAPIFunc( 'zCart', 'user', 'getImageName', array( 'ItemSKU' => $Item['SKU'], 'thumbnail' => true ) );

        // item fake properties addition
        preg_match("'<DIV[^>]*?>.*?</DIV>'si", $Item['Desc'], $ItemFakeProperties);
                $Item['ItemFakeProperties'] = $ItemFakeProperties[0];
                $Item['ItemFakeProperties'] = str_replace ( "<DIV>", "", $Item['ItemFakeProperties']);
                $Item['ItemFakeProperties'] = str_replace ( "</DIV>", "", $Item['ItemFakeProperties']);
                $Item['ItemFakeProperties'] = str_replace ( "<div>", "", $Item['ItemFakeProperties']);
                $Item['ItemFakeProperties'] = str_replace ( "</div>", "", $Item['ItemFakeProperties']);
                    $allowed = "<br><b><i><p><u><a><block><pre><center><hr>";
        $Item['ItemFakeProperties'] = strip_tags($Item['ItemFakeProperties'], $allowed);

        // removal of itemfakeproerties from item desc.
        $Item['Desc'] = preg_replace("'<div[^>]*?>.*?</div>'si", "", $Item['Desc']);
        return $Item;
    }
    return false;
}

/**
 *
 * getOrder
 * reads the customer data from the orders table
 *
 *@param $args['ON'] int order number
 *@return $Order['OrderNumber']
 *@return $Order['UserID']
 *@return $Order['OrderSubTotal']
 *@return $Order['OrderShippingTotal']
 *@return $Order['OrderTotal']
 *@return $Order['OrderPaymethodTotal']
 *@return $Order['UserData'] array
 *@return $Order['ShipToAddress'] array
 *@return $Order['CartData'] array
 * @return or false on error
 */
function zCart_userapi_getOrder( $args )
{
    extract( $args );
    if( isset( $ON ) )
    {
//      setlocale(LC_ALL, unserialize( pnModGetVar ('/PNConfig', 'locale') ) );
        $locale_info = localeconv();

        $Order = array();
        $result = pnModAPIFunc( 'zCart','user','readfromDB',
                         array('table' => 'orders',
                             'fields' => array('UserID', 'Date', 'CartData',
                                         'Address', 'ShipToAddress',
                                         'lastChange', 'OrderStatus' ),
                             'required' => array('OrderNumber', $ON ) ) );
        if( $result != false )
        {
            $Order['OrderNumber'] = $ON;
            list( $Order['UserID'],
                $Order['Date'],
                $cartdata,
                $userdata,
                $shiptoaddress,
                $Order['lastChange'],
                $Order['OrderStatus'] ) = $result;
            $Order['UserData'] = unserialize( stripslashes( $userdata ) );
            $Order['ShipToAddress'] = unserialize( stripslashes( $shiptoaddress ) );
            if( $Order['UserData']['UseShipTo'] != 'checked' )
            {
                // keep it simple - just copy the UserData fields to the ShipToAddress fields
                $Order['ShipToAddress']['ShipToName']     = $Order['UserData']['Name'];
                $Order['ShipToAddress']['ShipToAddress1'] = $Order['UserData']['Address1'];
                $Order['ShipToAddress']['ShipToAddress2'] = $Order['UserData']['Address2'];
                $Order['ShipToAddress']['ShipToZip']      = $Order['UserData']['Zip'];
                $Order['ShipToAddress']['ShipToCity']     = $Order['UserData']['City'];
                $Order['ShipToAddress']['ShipToState']    = $Order['UserData']['State'];
                $Order['ShipToAddress']['ShipToCountry']  = $Order['UserData']['Country'];
            }
            // build a itemarray with more information and
            // calculate values not longer stored in the db
            $cartdata = unserialize( stripslashes( $cartdata ) );
            $newcartdata = array();
            foreach( $cartdata['Items'] as $cartdataitem )
            {
                $newcartdataitem = array();
                $newcartdataitem['ItemID']       = $cartdataitem['ItemID'];
                $newcartdataitem['ItemSKU']      = $cartdataitem['ItemSKU'];
                $newcartdataitem['ItemName']     = $cartdataitem['ItemName'];
                $newcartdataitem['ItemQuantity'] = $cartdataitem['ItemQuantity'];
                $newcartdataitem['ItemDescription']= $cartdataitem['ItemDescription'];
                $newcartdataitem['ItemCost']     = $cartdataitem['ItemCost'];
                $newcartdataitem['ItemVAT']      = $cartdataitem['ItemVAT'];

                if (pnModGetVar('zCart', 'VatIncluded') != 'on')
                {
                    $newcartdataitem['ItemVATAmount'] = round( ( ( $newcartdataitem['ItemCost'] * $newcartdataitem['ItemVAT'] ) / 100), 2 );
                }
                else
                {
                    // rounding will result in rounding errors here
                    // modifier pncShowAsPrice will to this for us anyway
                    $newcartdataitem['ItemVATAmount'] = ( ( $newcartdataitem['ItemCost'] * $newcartdataitem['ItemVAT'] ) / 100);
                }
                $newcartdataitem['ItemVATAmountTotal'] = $newcartdataitem['ItemVATAmount'] * $newcartdataitem['ItemQuantity'];
                $newcartdataitem['ItemCostLong']  = $newcartdataitem['ItemCost'] + $newcartdataitem['ItemVATAmount'];
                $newcartdataitem['ItemCostTotal'] = $newcartdataitem['ItemCostLong'] * $newcartdataitem['ItemQuantity'];

                $newcartdataitem['ItemWeight']   = $cartdataitem['ItemWeight'];
                $newcartdataitem['ItemDelQty']   = $cartdataitem['ItemDelQty'];
                $newcartdataitem['ItemDone']     = $cartdataitem['ItemDone'];
                $newcartdataitem['ItemRemark']   = $cartdataitem['ItemRemark'];

                $newcartdata['Items'][] = $newcartdataitem;
            }
            $newcartdata['WeightTotal']         = $cartdata['WeightTotal'];
            $newcartdata['ItemsTotal']          = $cartdata['ItemsTotal'];
            $newcartdata['SubTotal']            = $cartdata['SubTotal'];
            $newcartdata['VATList']             = $cartdata['VATList'];
            $newcartdata['PaymethodFootermsg']  = $cartdata['PaymethodFootermsg'];
            $newcartdata['ShippingFootermsg']   = $cartdata['ShippingFootermsg'];
            // we have to take care about old style orders saved with old style finalmods here:
            if( isset( $cartdata['FinalModTotal'] ) )
            {
                // old style
                $newcartdata['OrderModifierTotal'] = $cartdata['FinalModTotal'];
            }
            else
            {
                // new style
                $newcartdata['OrderModifierTotal'] = $cartdata['OrderModifierTotal'];
                $newcartdata['OrderModifier']      = $cartdata['OrderModifier'];
            }
            $newcartdata['ShippingTotal']       = $cartdata['ShippingTotal'];
            $newcartdata['PaymethodTotal']      = $cartdata['PaymethodTotal'];
            $newcartdata['Total']               = $cartdata['Total'];
            $newcartdata['Remark']              = "";

            $Order['CartData'] = $newcartdata;

            // calulate VATTotal
            foreach( $Order['CartData']['VATList'] as $vat )
            {
                $vattotal += $vat;
            }
            $Order['CartData']['VATTotal'] = $vattotal;

            return $Order;
        }
    }
    return false;
}

/**
 * createOrder
 * creates a new order in the database
 *
 *We don't need the following parameters, we read them from the CartData field
 *$args['OrderSubTotal'], $args['OrderShippingTotal'],$args['OrderTotal'], $args['OrderPaymethodTotal']
 *@param $args['user'] array with user data
 *@param $args['cart'] array The full cartdata that we get from getCart, so we can decide only here what we want so save
 *@returns  'OrderNumber'
 */

function zCart_userapi_createOrder( $args )
{
    extract($args);
    if (!pnModAPILoad('zCart', 'user'))
    {
        return showerrorpage("unable to load pnuserapi", __FILE__, __LINE__);
    }

//  setlocale(LC_ALL, unserialize( pnModGetVar ('/PNConfig', 'locale') ) );
    // get the recent date and time
    $now = time();
    $OrderStatus = 0;

    // We save the last ordered ItemID in LastItemOrdered
    // When more than one item is in the cart, we save a random item
    $num = 0;
    if ( count( $cart['Items'] ) > 1)
    {
        // more than one item in the cart, we will choose one of it
        $num = mt_rand( 0, count( $cart['Items']) -1 );
    }
    pnModSetVar( 'zCart', 'LastItemOrdered', $cart['Items'][$num]['ItemID'] );

    // We now prepare the FinalCart - the array that is stored in the database and that
    // holds all the item ordered. This array has less entries than the original cart array
    // because we do not need to save such things like IgnoreQuantity or CartItemsID. So we
    // reduce the amount of diskspace used for the items.
    $FinalCart = array();
    $FinalCart['Items'] = array();
    foreach( $cart['CartItems'] as $ItemInCart )
    {
        $FinalItemInCart = array();
        $FinalItemInCart['ItemID']       = $ItemInCart['ItemID'];
        $FinalItemInCart['ItemSKU']      = $ItemInCart['ItemSKU'];
        $FinalItemInCart['ItemName']     = $ItemInCart['ItemName'];
        $FinalItemInCart['ItemQuantity'] = $ItemInCart['ItemQuantity'];
        $FinalItemInCart['ItemDesc']     = $ItemInCart['ItemDescription'];
        $FinalItemInCart['ItemCost']     = $ItemInCart['ItemCost'];
        $FinalItemInCart['ItemVAT']      = $ItemInCart['ItemVAT'];
        $FinalItemInCart['ItemWeight']   = $ItemInCart['ItemWeight'];
        $FinalItemInCart['ItemDelQty']   = 0;
        $FinalItemInCart['ItemDone']     = 0;
        $FinalItemInCart['ItemRemark']   = "";
        array_push( $FinalCart['Items'], $FinalItemInCart );
    }
    $FinalCart['WeightTotal'] = $cart['WeightTotal'];
    $FinalCart['ItemsTotal']  = $cart['ItemsTotal'];
    $FinalCart['SubTotal']    = $cart['SubTotal'];
    $FinalCart['VATList']     = $cart['VATList'];
/*
    if( count( $FinalCart['VATList']) > 0 )
    {
        $tmpKey = array_keys($FinalCart['VATList']);
        foreach($tmpKey as $key)
        {
            $FinalCart['VATList'][$key] = $FinalCart['VATList'][$key] ) );
        }
    }
*/
    $FinalCart['PaymethodFootermsg'] = $cart['PaymethodFootermsg'];
    $FinalCart['ShippingFootermsg']  = $cart['ShippingFootermsg'];
    $FinalCart['OrderModifierTotal'] = $cart['OrderModifierTotal'];
    $FinalCart['OrderModifier']      = $cart['OrderModifier'];
    $FinalCart['ShippingTotal']      = $cart['ShippingTotal'];
    $FinalCart['PaymethodTotal']     = $cart['PaymethodTotal'];
    $FinalCart['Total']              = $cart['Total'];
    $FinalCart['Remark']             = "";

    $CartData = addslashes( serialize( $FinalCart ) );
    $UserData = addslashes( serialize( $user ) );
    $s['ShipToName']     = $user['ShipToName'];
    $s['ShipToAddress1'] = $user['ShipToAddress1'];
    $s['ShipToAddress2'] = $user['ShipToAddress2'];
    $s['ShipToCity']     = $user['ShipToCity'];
    $s['ShipToState']    = $user['ShipToState'];
    $s['ShipToZip']      = $user['ShipToZip'];
    $s['ShipToCountry']  = $user['ShipToCountry'];
    $ShipToAddress = addslashes( serialize( $s ) );
    $UserID = $user['KID'];

    // insert new entry into Orders table
    $insertsql = "INSERT INTO ".pnConfigGetVar('prefix')."_zcart_orders
        (UserID, Date, lastChange, CartData,
        Address, ShipToAddress, OrderStatus)
        VALUES ('".pnVarPrepForStore($UserID)."', '".pnVarPrepForStore($now)."',
         '".pnVarPrepForStore($now)."',  '".pnVarPrepForStore($CartData)."',
        '".pnVarPrepForStore($UserData)."', '".pnVarPrepForStore($ShipToAddress)."',
        '".pnVarPrepForStore($OrderStatus)."')";
    $ON = pnModAPIFunc ('zCart', 'user', 'insertintoDB',
                      	  array('sql' => $insertsql,
                            	  'table' => 'orders',
                            	  'idfield' => 'OrderNumber'));
    if($ON===false)
    {
        pnSessionSetVar('errormsg',_PNC_DBERROR);
        return false;
    }
    return $ON;
}

/**
 * updateOrder
 * updates an existing order. ONl the data supplied as paramater will be updated,
 * everything else stays as is
 *
 *@param $args['ordernumber'] order number - mandatory
 *@param $args['cart'] array with cart information
 *@param $args['user'] array with user information
 *@param $args['shipto'] array with shipto address
 *@param $args['status'] orderstatus
 */
function zCart_userapi_updateOrder( $args )
{
    extract( $args );
    if( !isset( $ordernumber ) )
    {
        return false;
    }

    if( isset( $cart ) )
    {
        // remove the informatin from the array that have been calculated when reading the
        // order with getOrder()
        for( $i=0; $i<count($cart['CartData']['Items']); $i++ )
        {
            unset( $cart['CartData']['Items'][$i]['ItemVATAmount'] );
            unset( $cart['CartData']['Items'][$i]['ItemVATAmountTotal'] );
            unset( $cart['CartData']['Items'][$i]['ItemCostLong'] );
            unset( $cart['CartData']['Items'][$i]['ItemCostTotal'] );
        }
        $set = 'CartData = "' . pnVarPrepForStore( addslashes( serialize( $cart ) ) ) . '"';
    }
    if( isset( $user ) )
    {
        if( $set <> "" )
        {
            $set .= ", ";
        }
        $set .= "Address = '" . pnVarPrepForStore( addslashes( serialize( $user ) ) ) . "'";
    }
    if( isset( $shipto ) )
    {
        if( $set <> "" )
        {
            $set .= ", ";
        }
        $set .= "ShipToAddress = '" . pnVarPrepForStore( addslashes( serialize( $shipto ) ) ) . "'";

    }
    if( isset( $status ) )
    {
        if( $set <> "" )
        {
            $set .= ", ";
        }
        $set .= "OrderStatus = '" . pnVarPrepForStore( $status )."'";
    }
    if( $set <> "" )
    {
        $set .= ", ";
    }
    $set .= "lastChange = '" . pnVarPrepForStore( time() ) . "'";


    $sql = "UPDATE ".pnConfigGetVar('prefix')."_zcart_orders SET
           $set
           WHERE OrderNumber= '".(int)pnVarPrepForStore($ordernumber)."'";
    $success = pnModAPIFunc ('zCart', 'user', 'executesqlDB',
                             array( 'sql' => $sql ) );
    if($success===false)
    {
        pnSessionSetVar('errormsg',_PNC_DBERROR);
        return false;
    }
}

/**
 * getNumberOfItemsInCart
 * gets the number of items in the users cart
 *@args['KID'] string customer id
 *@returns integer number of items in the users cart or false on error
 */
function zCart_userapi_getNumberOfItemsInCart( $args )
{
    extract( $args );
    unset($args);

    if( isset($KID) )
    {
        list($dbconn, $tablename, $tablecolumn ) = pncOpenDB('zcart_cartitems');
        $sql = "COUNT *
                FROM $tablename
    	        WHERE $tablecolumn[UserID]='".pnVarPrepForStore($KID)."'";
        $result = $dbconn->Execute($sql);
        // check for errors or no rows found, and if so return false
        if (($dbconn->ErrorNo() != 0) || ($result->EOF) ) { return false; }
        list($cartitemcount) = $result->fields;
        pncCloseDB($result);
        return $cartitemcount;
    }
    else
    {
        return false;
    }
}

/**
 * countSubCategories
 * gets the number of sub categories in category
 *@args['cid'] int category id
 *@returns integer number of sub categories or false on error
 */
function zCart_userapi_countSubCategories( $args )
{
    extract( $args );
    unset($args);
    if( isset($cid) ) {
        list($dbconn, $tablename, $tablecolumn ) = pncOpenDB('zcart_categories');
        $sql = "SELECT $tablecolumn[CategoryID]
                FROM $tablename
    	        WHERE $tablecolumn[CatParent]='".(int)pnVarPrepForStore($cid)."'";
        $result = $dbconn->Execute($sql);
        // check for errors or no rows found, and if so return false
        if (($dbconn->ErrorNo() != 0) || ($result->EOF) ) { return false; }
        $subcatcount = $result->RecordCount();
        pncCloseDB($result);
        return $subcatcount;
    } else {
        return false;
    }
}

/**
 * getUserData
 * gets all the information about an user that are stored in the db
 *@args['KID'] string customer id
 *@returns array:
 */
function zCart_userapi_getUserData( $args )
{
    extract( $args );
    if( $KID )
    {
        $user = array();
        $user['KID'] = $KID;
        list(
            $user['ID'],
            $user['Name'],
            $user['Address1'],
            $user['Address2'],
            $user['City'],
            $user['State'],
            $user['Zip'],
            $user['Country'],
            $user['Email'],
            $user['DayPhone'],
            $user['EvePhone'],
            $user['PayMethod'],
            $temp1,                 // serialized field PayMethodData
            $user['ShipMethod'],
            $temp2,                 // serialized field ShippingMethodData
            $user['VATIdentNumber'],
            $user['Business'],
            $user['Date'],
            $user['ShipToName'],
            $user['ShipToAddress1'],
            $user['ShipToAddress2'],
            $user['ShipToCity'],
            $user['ShipToState'],
            $user['ShipToZip'],
            $user['ShipToCountry']
            ) = pnModAPIFunc( 'zCart', 'user', 'readfromDB',
                       array( 'table' => 'users',
                              'fields' => array( 'UserID', 'Name', 'Address1', 'Address2',
                                                 'City', 'State', 'Zip', 'Country', 'Email',
                                                 'DayPhone', 'EvePhone', 'PayMethod',
                                                 'PayMethodData', 'ShippingMethod',
                                                 'ShippingMethodData', 'VATIdentNumber', 'Business',
                                                 'Date', 'ShipToName',
                                                 'ShipToAddress1', 'ShipToAddress2',
                                                 'ShipToCity', 'ShipToState', 'ShipToZip',
                                                 'ShipToCountry' ),
                              'required' =>array('UserName', $KID) ) );
            $user['PayMethodData']  = unserialize( $temp1 );
            $user['ShipMethodData'] = unserialize( $temp2 );
            if( !isset($user['Business']) )
            {
                $user['Business'] = 0;
            }
            $user['TaxExempt'] = ( $user['Business'] == 1 ) ? "checked" : "";
/*
            if( $user['Business'] == 1 )
            {
                $user['TaxExempt'] = "checked";
            }
            else
            {
                $user['TaxExempt'] = "";
            }
*/
        return $user;
    }
    else
    {
        return false;
    }
}

/**
 * setUserData
 * write all information about an user into the db
 *@args['user'] array with user data fields
 *@args['newuser'] boolean true, when we have to add a new user
 *@returns boolean true on success, otherwise false
 */
function zCart_userapi_setUserData( $args )
{
    extract( $args );

    if( $user )
    {
        if( $newuser == false )
        {
            $user['Business'] = ( $user['TaxExempt'] == 'checked' ) ? 1 : 0;
/*
            if( $user['TaxExempt'] == 'checked' )
            {
                $user['Business'] = 1;
            }
            else
            {
                $user['Business'] = 0;
            }
*/
            $sql = "UPDATE ".pnConfigGetVar('prefix')."_zcart_users SET
                Name='".                 pnVarPrepForStore($user['Name'])."',
                Address1='".             pnVarPrepForStore($user['Address1'])."',
                Address2='".             pnVarPrepForStore($user['Address2'])."',
                City='".                 pnVarPrepForStore($user['City'])."',
                State='".                pnVarPrepForStore($user['State'])."',
                Zip='".                  pnVarPrepForStore($user['Zip'])."',
                Country='".              pnVarPrepForStore($user['Country'])."',
                Email='".                pnVarPrepForStore($user['Email'])."',
                DayPhone='".             pnVarPrepForStore($user['DayPhone'])."',
                EvePhone='".             pnVarPrepForStore($user['EvePhone'])."',
                PayMethod='".            pnVarPrepForStore($user['PayMethod'])."',
                PayMethodData='".        pnVarPrepForStore( serialize($user['PayMethodData']))."',
                ShippingMethod='".       pnVarPrepForStore($user['ShipMethod'])."',
                ShippingMethodData='".   pnVarPrepForStore( serialize($user['ShipMethodData']))."',
                VATIdentNumber='".       pnVarPrepForStore($user['VATIdentNumber'])."',
                Business='".             pnVarPrepForStore($user['Business'])."',
                Date='".                 time()."',
                ShipToName='".           pnVarPrepForStore($user['ShipToName'])."',
                ShipToAddress1='".       pnVarPrepForStore($user['ShipToAddress1'])."',
                ShipToAddress2='".       pnVarPrepForStore($user['ShipToAddress2'])."',
                ShipToCity='".           pnVarPrepForStore($user['ShipToCity'])."',
                ShipToState='".          pnVarPrepForStore($user['ShipToState'])."',
                ShipToZip='".            pnVarPrepForStore($user['ShipToZip'])."',
                ShipToCountry='".        pnVarPrepForStore($user['ShipToCountry'])."'
                WHERE UserName='".pnVarPrepForStore($user['KID'])."'";
        }
        else
        {
            $sql = "INSERT INTO ".pnConfigGetVar('prefix')."_zcart_users SET
                UserName='".             pnVarPrepForStore($user['KID'])."',
                Name='".                 pnVarPrepForStore($user['Name'])."',
                Address1='".             pnVarPrepForStore($user['Address1'])."',
                Address2='".             pnVarPrepForStore($user['Address2'])."',
                City='".                 pnVarPrepForStore($user['City'])."',
                State='".                pnVarPrepForStore($user['State'])."',
                Zip='".                  pnVarPrepForStore($user['Zip'])."',
                Country='".              pnVarPrepForStore($user['Country'])."',
                Email='".                pnVarPrepForStore($user['Email'])."',
                DayPhone='".             pnVarPrepForStore($user['DayPhone'])."',
                EvePhone='".             pnVarPrepForStore($user['EvePhone'])."',
                PayMethod='".            pnVarPrepForStore($user['PayMethod'])."',
                PayMethodData='".        pnVarPrepForStore( serialize($user['PayMethodData']))."',
                ShippingMethod='".       pnVarPrepForStore($user['ShipMethod'])."',
                ShippingMethodData='".   pnVarPrepForStore( serialize($user['ShipMethodData']))."',
                VATIdentNumber='".       pnVarPrepForStore($user['VATIdentNumber'])."',
                Business='".             pnVarPrepForStore( $user['Business'])."',
                Date='".                 time()."',
                ShipToName='".           pnVarPrepForStore($user['ShipToName'])."',
                ShipToAddress1='".       pnVarPrepForStore($user['ShipToAddress1'])."',
                ShipToAddress2='".       pnVarPrepForStore($user['ShipToAddress2'])."',
                ShipToCity='".           pnVarPrepForStore($user['ShipToCity'])."',
                ShipToState='".          pnVarPrepForStore($user['ShipToState'])."',
                ShipToZip='".            pnVarPrepForStore($user['ShipToZip'])."',
                ShipToCountry='".        pnVarPrepForStore($user['ShipToCountry'])."'";
        }
      //echo $sql;
        return pnModAPIFunc( 'zCart', 'user', 'executesqlDB',
                             array( 'sql' => $sql ) );
    }
    else
    {
        // no user data submitted
        return false;
    }
}

/**
 * readActiveMethods
 * scans the zCart directory for pnXX*ap.php files, check if they are activated
 * and adds them to an array if yes
 *@param args['type'] string either pm (Paymethods) or sm (ShipMethods) in the moment
 *@returns array with method names (without pnXX and api.php)
 */
function zCart_userapi_readActiveMethods( $args )
{
    extract( $args );
    $methods = array();
    $dir = opendir ( "modules/zCart" );
    while ( $m = readdir( $dir ) )
    {
        if ( ereg("pn$type", $m) )
        {
            // remove trailing api.php
            $m = str_replace("api.php", "", $m);
            // remove leading pn
            $m = substr( $m, 2, strlen($m) - 2 );
            if ( pnModGetVar('zCart', $m) == 'on' )
            {
                // paymethod is active
                if (pnSecAuthAction(0, 'zCart::method', $args['type'].":$m:", ACCESS_COMMENT)){
                    $methods[] = $m;
                }
            }
        }
    }
    return $methods;
}

/**
 * getInvoice
 * reads a invoice from the database
 *@param args['ON'] int ordernumber
 *@returns array
 *@invoice['data']
 *@invoice['type'] int (1 = html)
 *@invoice['ordernumber']
 *@invoice['userid'] string customer id
 */
function zCart_userapi_getInvoice( $args )
{
    extract( $args );
    if( pnSecAuthAction(0, 'zCart::', '::', ACCESS_ADMIN ) )
    {
        $result = pnModAPIFunc( 'zCart', 'user', 'readfromDB',
                                array( 'table' => 'invoices',
                                       'fields' => array( 'Invoice', 'Type', 'UserID' ),
                                       'required' => array( 'OrderNumber', $ON ) ) );
    }
    else
    {
        // usermode - this might deliver a false when someone tries to read an invoice he is not sllowed to see
        $KID = pnSessionGetVar( 'PNCUser' );
        $result = pnModAPIFunc( 'zCart', 'user', 'readfromDB',
                                array( 'table' => 'invoices',
                                       'fields' => array( 'Invoice', 'Type', 'UserID' ),
                                       'required' => array( 'OrderNumber', $ON, 'UserID', $KID ) ) );
    }
    if( $result <> false )
    {
        // prepare array to return
        $inv = array();
        $inv['ordernumber']  = $ON;
        list ( $data, $inv['type'], $inv['userid'] ) = $result;
        $inv['data'] = stripslashes( $data );
        return $inv;
    }
    return false;
}

/**
 * setInvoice
 * writes an invoice to the database
 *@param args['KID'] string customer id
 *@param args['ON'] int order number
 *@param args['type'] int type of data (1 = html)
 *returns the same array as in getInvoice or false on error
 */
function zCart_userapi_setInvoice( $args )
{
    extract( $args );

    $order = pnModAPIFunc( 'zCart', 'user', 'getOrder',
                            array( 'ON' => $ON ) );

    $invoice =& new pnRender('zCart');
    $invoice->caching = false;
    $invoice->assign( 'Order', $order );
    $invoice->assign( 'InvoiceLinkUrl', pnModAPIFunc( 'zCart', 'user', 'pncModURL', array( 'Section' => 'user', 'Function' => 'receipt', 'Args' => array( 'ON' => $ON, 'KID' => $KID ) ) ) );
    $invoicetext = $invoice->fetch( pnModAPIFunc( 'zCart', 'user', 'GetTemplateByID', array( 'TemplateID' => pnModGetVar( 'zCart', 'PrintInvoiceTemplateID' ) ) ) );

    if( $invoicetext )
    {
        $content = addslashes( $invoicetext );
        $type = 1; // 1 = html
        // now we can finally store $content into the invoices table

        $sql = "INSERT INTO ".pnConfigGetVar('prefix')."_zcart_invoices
                (UserID,
                 OrderNumber,
                 Type,
                 Invoice) VALUES
                ('".pnVarPrepForStore($KID)."',
                  '".(int)pnVarPrepForStore($ON)."',
                  '".(int)pnVarPrepForStore($type)."',
                 '".pnVarPrepForStore($content)."')";
        if( pnModAPIFunc( 'zCart', 'user', 'executesqlDB',
                      array('sql' => $sql ) ) == true )
        {
            // succesful saved the invoice - return it to the calling function
            $inv = array();
            $inv['UserID'] = $KID;
            $inv['Ordernumber'] = $ON;
            $inv['data'] = $invoicetext;
            $inv['type'] = $type;
            return $inv;
        }
    }
    // no success - return false
    return false;
}

/**
 * isHTML
 * checks if mail is in html format. If we find <html> and </html> in the text we assume it is
 *@param args['mailbody'] string with mailbody
 *@returns true if html
 *@returns false if not html (plain text)
 *
 */
function zCart_userapi_isHTML( $args )
{
    extract( $args );
    // We will now determine if the mail is in html format. If we find <html> and </html> in the
    // body we assume HTML - this is mentioned in the documentation of pnc !
    // I think we are quite sure in this case...
    // We need this to add the necessary header lines to the mail so that the users mailclient
    // can handle the html mail
    if ( ereg( "<html>", strtolower( $mailbody ) ) AND ereg( "</html>", strtolower( $mailbody ) ) )
    {
        // html
        return true;
    }
    return false;
}

/**
 * sendEmail
 * sends the email containing the invoice to the customer or shop owner
 *@param args['KID'] string customer id
 *@param args['ON'] int ordernumber
 *@param args['customer'] boolean if true, we send it to the customer, if false, we send it
                          to the shop owner
 *@returns bool  true on success or false if an error occured
 */
function zCart_userapi_sendEmail( $args )
{
    extract( $args );
    $templateID = ( $customer == true ) ? pnModGetVar( 'zCart', 'MailTemplateID' ) : pnModGetVar( 'zCart', 'InternalMailTemplateID' );

    $invoice =& new pnRender('zCart');
    $invoice->caching = false;
    $order = pnModAPIFunc( 'zCart', 'user', 'getOrder',
                           array( 'ON' => $ON ) );
    $invoice->assign( 'Order', $order );
    $invoice->assign( 'InvoiceLinkUrl', pnModAPIFunc( 'zCart', 'user', 'pncModURL', array( 'Section' => 'user', 'Function' => 'receipt', 'Args' => array( 'ON' => $ON, 'KID' => $KID ) ) ) );
    $invoicetext = $invoice->fetch( pnModAPIFunc( 'zCart', 'user', 'GetTemplateByID', array( 'TemplateID' => $templateID ) ) );

    if( $customer == true )
    {
        $to   = $order['UserData']['Email'];
        $from = pnModGetVar( 'zCart', 'Email' );
    }
    else
    {
        $from  = pnModGetVar( 'zCart', 'Email' );
        $to    = $from;
    }
    $header = "From: $from\nX-Mailer: zCart ".pnModGetVar( 'zCart', 'Version' )." using PHP/".phpversion();
    $html = 0;
    if( pnModAPIFunc( 'zCart', 'user', 'isHTML', array( 'mailbody' => $invoicetext ) ) == true )
    {
        // html
        $header .= "\nMIME-Version: 1.0\nContent-type: text/html";
        $html = 1;
    }
    // mail to the customer
//    return pnMail( $to, ""._PNC_EMAILSUBJECT." $ON", $invoicetext, $header, $html);
    return mail( $to, ""._PNC_EMAILSUBJECT." $ON", $invoicetext, $header );

}
/**
 * countItemsInCategory
 * returns the number of items in a given category
 *@param $args['CID'] int CategoryID
 *@returns int number of items in CID
 */
function zCart_userapi_countItemsInCategory($args)
{
    extract($args);
    unset($args);

    $lim = "WHERE Category='".(int)pnVarPrepForStore($CID)."'";
    $lim2 = "WHERE CatParent='".(int)pnVarPrepForStore($CID)."'";
    $found = 1;
    $foundincr = 1;
    $num_items = 0;
    while ( $foundincr )
    {
        $Query = "SELECT CategoryID FROM ".pnConfigGetVar('prefix')."_zcart_category ".$lim2;
        $result = zCart_userapi_readfromDBpreformat(array('sql' => $Query));
        $lim2 = "";
        $foundincr = zCart_userapi_readfromDBnumrowspreformat (array('sql' => $Query));  // count($result2);
        $found = $found + $foundincr;
        $count = 0;
        if ( $result <> false )
        {
            foreach($result as $resultline)
            {
                list( $cat ) = $resultline;
                if ( !$count )
                {
                    $lim2 = "CatParent='".pnVarPrepForStore($cat)."'";
                }
                else
                {
                    $lim2 = $lim2." or CatParent='".pnVarPrepForStore($cat)."'";
                }
                $count++;
            }
        }
        if ( $lim2)
        {
            $lim3 = str_replace("CatParent", "Category", $lim2);
            $lim = $lim." or ".$lim3;
        }
        $lim2 = "WHERE ".$lim2;
    }
    $Query = "SELECT ItemID FROM ".pnConfigGetVar('prefix')."_zcart_items $lim";
    $result = zCart_userapi_readfromDBpreformat(array('sql' => $Query));
    if ( $result <> false )
    {
        return count($result);
    }
    return 0;
}

/**
 * readCategoryList
 * reads the categories inside a given category
 *@param args['StartCategoryID'] int category where to start reading the tree,
 *                                   when false, start at the root category
 *@returns array of categories
 *@return []['CategoryID'] the id
 *@return []['CategoryName'] the name
 *@return []['Sequence'] the sequence number of the category
 *@return []['URL'] link to the category
 *@return []['Items'] number of items in this and all subcategories
 *@return []['Image'] path to fullsize image file or false
 *@return []['ImageTN'] path to thumbnail image file or false
 */
function zCart_userapi_readCategoryList( $args )
{
    extract($args);
    unset($args);
    $num_items = 0;
    $result= pnModAPIFunc( 'zCart', 'user', 'readmultiplefromDB',
                           array( 'table'    => 'categories',
                                  'fields'   => array( 'pn_category_id', 'pn_category_data' ),
                                  'required' => array( 'pn_category_parent', $StartCategoryID, 'pn_category_visible', 1 ) ) );
    if ( $result <> false )
    {
        $num_categories = count($result);
        if ( $num_categories )
        {
            $count = 0;
            foreach ($result as $resultline)
            {
                list( $CategoryList[$count]['ID'],
                      $name ) = $resultline;
                if( is_serialized( $name ) == false )
                {
                    $CategoryList[$count]['Name'] = $name;
                    $CategoryList[$count]['Sequence'] = 9999;
                }
                else
                {
                    $c_hack = unserialize( $name );
                    $CategoryList[$count]['Name'] = $c_hack['name'];
                    $CategoryList[$count]['Sequence'] = $c_hack['sequence'];
                }
                $CategoryList[$count]['URL'] = pncUserAPIModURL( 'zCart','user', 'categoryview',
                                                           array( 'CategoryID' => $CategoryList[$count]['ID'] ) );
                $CategoryList[$count]['Items'] = pnModAPIFunc( 'zCart', 'user', 'countItemsInCategory',
                                                        array( 'CID' => $CategoryList[$count]['ID'] ) );
                $CategoryList[$count]['Image']   = pnModAPIFunc('zCart','user','getImageName', array('ItemSKU' => $CategoryList[$count]['ID'], 'imagefolder'=>'category_images')) ;
                $CategoryList[$count]['ImageTN'] = pnModAPIFunc('zCart','user','getImageName', array('ItemSKU' => $CategoryList[$count]['ID'], 'thumbnail'=>true, 'imagefolder'=>'category_images')) ;

                $count++;
            }
            usort( $CategoryList, "cmp_sequence" );
        }
    }
    return $CategoryList;
}

/**
 * internal function to compare two CategorySequence numbers - needed for sorting by sequence
 *
 */
function cmp_sequence ($a, $b)
{
   if ((int)$a['Sequence'] == (int)$b['Sequence']) return 0;
   return ((int)$a['Sequence'] < (int)$b['Sequence']) ? -1 : 1;
}

/**
 * getItemQuery
 * executes the query command as prepared in user_handlesearch or user_categoryview and returns
 * an array of array with information about the found items
 *
 *@param args['query'] string sql command
 *@returns array of array of information
 *@return array[NumberofItem]array_with_iteminformation
 * the array_with_iteminformation is identical with the one returned from getItem()
 */
function zCart_userapi_getItemQuery( $args )
{
    extract( $args );
    $result = zCart_userapi_readfromDBpreformat( array( 'sql' => $query ) );

    $itemsarray = array();
    if( $result != false )
    {
        foreach( $result as $resultline )
        {
            list ( $ID ) = $resultline;
/*            $Item['Category']=pnModAPIFunc( 'zCart', 'user','GetCategoryName',array('CategoryID'=>$Item['CategoryID']));

            if( $VATID != 0 )
            {
                $val = split ( "[.,]", pnModGetVar( 'zCart', 'VATID'.$VATID ) );
            }
            else
            {
                $val = split ( "[.,]", pnModAPIFunc( 'zCart', 'user', 'GetVATbyItemID',
                                    array( 'ItemID' => $Item['ID'],
                                         'CID' => $Item['CategoryID'] ) ) );
            }
            $Item['Vat'] = $val[0] + ( $val[1] / 10 );
            $val = split ( "[.,]", $Cost );
            $Item['Cost'] = $val[0] + ( $val[1] / 100 );
            $Item['VatAmount'] 	= round( ( ( $Item['Cost'] * $Item['Vat'] ) / 100), 2 );
            $Item['CostLong']  	= $Item['Cost'] + $Item['VatAmount'];
            $Item['Image']   = pnModAPIFunc( 'zCart', 'user', 'getImageName', array( 'ItemSKU' => $Item['SKU'] ) );
            $Item['ImageTN'] = pnModAPIFunc( 'zCart', 'user', 'getImageName', array( 'ItemSKU' => $Item['SKU'], 'thumbnail' => true ) );

            // item fake properties addition
            preg_match("'<DIV[^>]*?>.*?</DIV>'si", $Item['Desc'], $ItemFakeProperties);
            $Item['ItemFakeProperties'] = $ItemFakeProperties[0];
            $Item['ItemFakeProperties'] = str_replace ( "<DIV>", "", $Item['ItemFakeProperties']);
            $Item['ItemFakeProperties'] = str_replace ( "</DIV>", "", $Item['ItemFakeProperties']);
            $Item['ItemFakeProperties'] = str_replace ( "<div>", "", $Item['ItemFakeProperties']);
            $Item['ItemFakeProperties'] = str_replace ( "</div>", "", $Item['ItemFakeProperties']);
            $allowed = "<br><b><i><p><u><a><block><pre><center><hr>";
            $Item['ItemFakeProperties'] = strip_tags($Item['ItemFakeProperties'], $allowed);
            // removal of itemfakeproerties from item desc.
            $Item['Desc'] = preg_replace("'<div[^>]*?>.*?</div>'si", "", $Item['Desc']);
*/
            $Item=zCart_userapi_getItem( array('ItemID'=>$ID) );
            //ignore items that we are not allowed to even see
            //Further checks should be applied when this result is processed because the context is not clear here
            if (pnSecAuthAction(0, 'zCart::item', $Item['SKU'].'::'.$Item['ID'], ACCESS_OVERVIEW)
                  &&pnSecAuthAction(0, 'zCart::category', $Item['Category'].'::'.$Item['CategoryID'], ACCESS_OVERVIEW))
             {
                   $itemsarray[] = $Item;
             }
        }
        return $itemsarray;
    }
    return false;
}

/**
 * getCategory
 * Reads the category information from the database and returns them in an array
 *
 *@param $args['CategoryID'] category id
 *@returns array
 *@return['ID'] category id
 *@return['Name'] category name
 *@return['ParentID'] category parent id
 *@return['Invisible'] true or false
 *@return['Vat'] vat (not the ID, the percentage value)
 */
function zCart_userapi_getCategory( $args )
{
    extract( $args );
    $cat = array();
    if( $CategoryID <> -1 )
    {
        $result = zCart_userapi_readfromDB( array( 'table' => 'categories',
                                                        'fields' => array( 'category_data', 'category_parent', 'category_visible', 'vat_id',
                                                                           'category_intro_template_id ','category_view_template_id' ),
                                                        'required' => array( 'category_id', $CategoryID ) ) );
        if( $result <> false )
        {
            $cat['ID'] = $CategoryID;
            list(
                $name,
                $cat['ParentID'],
                $invisible,
                $cat['VatID'],
                $cat['CategoryViewTemplateID'],
                $cat['ItemViewTemplateID'] ) = $result;

            // if $name is serialized, its an arrayx containing name and sequence number
            if( is_serialized( $name ) == false )
            {
                // not serialized - its a real name;
                $cat['Name'] = $name;
                $cat['Sequence'] = 9999;
            }
            else
            {
                // serialized its an array
                $c_hack = unserialize( $name );
                $cat['Name']     = $c_hack['name'];
                $cat['Sequence'] = $c_hack['sequence'];
            }

            if( $cat['VatID'] != 0 )
            {
                $val = split ( "[.,]", pnModGetVar( 'zCart', 'VATID'.$cat['VatID'] ) );
                $cat['Vat'] = $val[0] + ( $val[1] / 10 );
                $cat['TrueVatID'] = true;
            }
            else
            {
                $VatResult=pnModAPIFunc('zCart','user','getCategoryVAT', array('CategoryID'=>$CategoryID ) );
                $cat['VatID'] = $VatResult['VATID'];
                $cat['Vat'] = $VatResult['VAT'];
                $cat['TrueVatID'] = false;
            }
            $cat['Vat'] = $val[0] + ( $val[1] / 10 );
            $cat['Invisible'] = false;
            if( $invisible == '0' )
            {
                $cat['Invisible'] = true;
                $cat['InvisibleHTML'] = "checked";
            }
            // get the catgory image names
            $cat['Image'] = pnModAPIFunc('zCart','user','getImageName', array('ItemSKU' => $cat['ID'],  'imagefolder'=>'category_images')) ;
            $cat['ImageTN'] = pnModAPIFunc('zCart','user','getImageName', array('ItemSKU' => $cat['ID'], 'thumbnail'=>true, 'imagefolder'=>'category_images')) ;

            //get category parents name
            if( $cat['ParentID'] <> 0 )
            {
                list( $pname ) = pnModAPIFunc( 'zCart', 'user', 'readfromDB',
                                                array( 'table' => 'category',
                                                       'fields' => array( 'Category' ),
                                                       'required' => array( 'CategoryID', $cat['ParentID'] ) ) );
                // if $pname is serialized, its an array containing name and sequence number
                if( is_serialized( $pname ) == false )
                {
                    // not serialized - its a real name;
                    $cat['ParentName'] = $pname;
                }
                else
                {
                    // serialized its an array
                    $c_hack = unserialize( $pname );
                    $cat['ParentName']     = $c_hack['name'];
                }
            }
            $cat['ItemCount'] = pnModAPIFunc( 'zCart', 'user', 'countItemsInCategory',
                                              array( 'CID' => $CategoryID ) );
/*
            $cat['SubCategoryCount'] = pnModAPIFunc( 'zCart', 'user', 'readfromDBnumrows',
                                                     array( 'table' => 'category',
                                                            'fields' => array( 'CategoryID' ),
                                                            'required' => array( 'CatParent', $CategoryID ) ) );
*/
            $cat['SubCategoryCount'] = pnModAPIFunc( 'zCart', 'user', 'countSubCategories',
                                                     array( 'cid' => $CategoryID ) );
        }
        else
        {
            return false;
        }
    }
    else
    {
        // cid is -1 which means we have to create an "new category array"
        $cat['ID'] = -1;
        $cat['Name'] = "";
        $cat['ParentID'] = 0;
        $cat['Sequence'] = 9999;
        $cat['ParentName'] = "";
        $cat['Vat'] = 0;
        $cat['VatID'] = 0;
        $cat['TrueVatID'] = false;
        $cat['Invisible'] = false;
        $cat['InvisibleHTML'] = "";
        $cat['CategoryViewTemplateID'] = 0;
        $cat['ItemViewTemplateID'] = 0;
        $cat['Image'] = false;
        $cat['ImageTN'] = false;
        $cat['ItemCount'] = 0;
        $cat['SubCategoryCount'] = 0;
    }
   if (!(pnSecAuthAction(0, 'zCart::item', $Item['SKU'].'::'.$Item['ID'], ACCESS_OVERVIEW)
          &&pnSecAuthAction(0, 'zCart::category', $Item['Category'].'::'.$Item['CategoryID'], ACCESS_OVERVIEW)))
     {
            return showerrorpage(_PNC_NOAUTH, __FILE__, __LINE__);
     }
     return $cat;

}

/**
 * get the valid CategoryView-, ItemList- or ItemViewTemplateID by searching the category tree if necessary
 *@param $args['CID'] CategoryID
 *@param $args['TemplateType'] string, either 'CategoryViewTemplateID' or 'ItemViewTemplateID'
 *@returns int[2] valid TemplateID
 */
function zCart_userapi_GetTemplateID ($args)
{
    extract($args);
    while ($CID)
    {
        list($TemplateID, $CID) = zCart_userapi_readfromDB(array('table' => 'category',
                                                                'fields' => array( "$TemplateType", 'CatParent'),
                                                                'required' => array('CategoryID', $CID)));
        if ($TemplateID != 0 )
        {
            // CatParent has a valid TemplateID, so we use this
            return $TemplateID;
        }
    }
    // we search all CatParents without finding a valid TemplateID,
    // so we use the default value set in the shop config
    // name inconsistencies:
    if( $TemplateType == 'CatIntroTemplateID' )
    {
        $TemplateType = 'CategoryViewTemplateID';
    }
    return pnModGetVar('zCart', 'Default'.$TemplateType);
}

/**
 * getFederalStateListForSelect
 * prepares a dropdown list with names of federal states, currently usa and canada only
 * if vraiblename is not set we do not add <select></select> and return the <option>s only
 *@param $args['VariableName'] string, mandatory, the variable name that will contain the selection
 *@param $args['Country'] string, mandatory, country name, 'usa' or 'canada' for now
 *@param $args['SelectedState'] string, optional, state for preselection
 *@param $args['Format'] string, optional, 'long' or 'short' state names
 *@returns string with complete dropdown list or false on error
 */
function zCart_userapi_getFederalStateListForSelect( $args )
{
    extract( $args );

    if( !$Country )
    {
        return false;
    }
    if( ($Format) AND ( ( $Format <> 'long' ) AND ( $Format <> 'short' ) ) )
    {
        return false;
    }

    $usa = ""._PNC_USA;
    $canada = ""._PNC_CANADA;
    switch( $Country )
    {
        case "$usa":
                $pleaseselect = pnVarPrepForDisplay(_PNC_SELECTSTATE);
                if( $Format == 'long' )
                {
                    $statelist = ""._PNC_USSTATESLONG;
                }
                else
                {
                    $statelist = ""._PNC_USSTATES;
                }
                break;
        case "$canada":
                $pleaseselect = pnVarPrepForDisplay(_PNC_SELECTPROVINCE);
                if( $Format == 'long' )
                {
                    $statelist = ""._PNC_CAPROVINCESLONG;
                }
                else
                {
                    $statelist = ""._PNC_CAPROVINCES;
                }
                break;
        default:
                return false;
                break;
    }

	$statelist = split(",", $statelist);

    $temp = "";
    if( $VariableName )
    {
        $temp = "<select name='$VariableName' size='1'>\n";
    }

    if( $SelectedState )
    {
        $temp .= "<option value='$SelectedState' selected>$SelectedState</option>\n";
    }
    $temp .= "<option value='' >$pleaseselect</option>\n";
    foreach( $statelist as $state )
    {
        $temp .= "<option value='$state' >$state</option>\n";
    }
    if( $VariableName )
    {
        $temp .= "</select>\n";
    }
    return $temp;
}

/**
 * removeItemFromCart
 *@params $args['CartItemID']
 *@params $args['KID']
 */
function zCart_userapi_removeItemFromCart( $args )
{
    extract( $args );
    $result = pnModAPIFunc ( 'zCart', 'user', 'readfromDB',
                             array( 'table' => 'cartitems',
                                    'fields' => array('ItemQuantity', 'ItemID'),
                                    'required' => array('CartItemsID', $CartItemID, 'UserID', $KID)));
    if ( $result != false )
    {
        list( $InCartQty, $ItemID ) = $result;
        $InCartQty = intval($InCartQty);
        // now read th neessary item data
        $result2 = pnModAPIFunc( 'zCart', 'user', 'readfromDB',
                                 array( 'table' => 'items',
                                        'fields' => array( 'QuantityOrdered' ),
                                        'required' => array('ItemID', $ItemID )));
        if( $result2 != false )
        {
            list( $OrderedQty ) = $result2;
            // take the item out of the art now
            $OrderedQty = $OrderedQty - $InCartQty;
            // save item information back to the database
            $sql = "UPDATE ".pnConfigGetVar('prefix')."_zcart_items SET QuantityOrdered='".(int)pnVarPrepForStore($OrderedQty)."' WHERE ItemID='".(int)pnVarPrepForStore($ItemID)."'";
            if( pnModAPIFunc( 'zCart', 'user', 'executesqlDB',
                              array( 'sql' => $sql ) ) <> false )
            {
                // item adjusted, remove cartitems now
                pnModAPIFunc( 'zCart', 'user', 'executesqlDB',
                              array( 'sql' => "DELETE FROM ".pnConfigGetVar('prefix')."_zcart_cartitems WHERE CartItemsID='".pnVarPrepForStore($CartItemID)."' AND UserID='".pnVarPrepForStore($KID)."'"));
                return true;
            }
        }
    }
    // something went wrong, return error
    return false;
}

/**
 * updateCartOwnership
 *
 * changes the ownership of cartitems from $oldowner to $newowner
 *
 *@param $args['oldowner'] string the name of the old cart owner
 *@param $args['newowner'] string the name of the new cart owner
 *@returns boolean, true on success, otherwise false
 */
function zCart_userapi_updateCartOwnership( $args )
{
    extract( $args );
    if( ( !$oldowner | !$newowner ) | ($oldowner == $newowner) )
    {
        return false;
    }

    $sql = "UPDATE ".pnConfigGetVar('prefix')."_zcart_cartitems SET UserID='".pnVarPrepForStore($newowner)."' WHERE UserID='".pnVarPrepForStore($oldowner)."'";
    return pnModAPIFunc( 'zCart', 'user', 'executesqlDB',
                         array( 'sql' => $sql ) );
}

/**
 * getOrdersByUser
 * read all orders that belong to a given user id
 *
 *@param $args['user'] string the customers id
 *@return array of orders as returned by getOrder
 */
function zCart_userapi_getOrdersByUser( $args )
{
    extract( $args );
    if( $user )
    {
        $result = pnModAPIFunc( 'zCart', 'user', 'readmultiplefromDB',
                                array( 'table' => 'orders',
                                       'fields' => array( 'OrderNumber' ),
                                       'required' => array( 'UserID', $user ) ) );
        if( $result <> false )
        {
            $orderarray = array();
            foreach( $result as $resultline )
            {
                list( $on ) = $resultline;
                // we fille the array even if the order cannot be loaded, the handling of this
                // has to be done in the template
                $orderarray[$on] = pnModAPIFunc( 'zCart', 'user', 'getOrder', array( 'ON' => $on ) );
            }
            return $orderarray;
        }
    }
    // an error occured
    return false;
}

/**
 * applyModifiers
 * call all active order modifiers
 *
 */
function zCart_userapi_applyModifiers()
{
}

/**
 * getOrdersByUser
 * read all orders that belong to a given user id
 *
 *@param $args['CategoryID'] integer, the ID of the selected category
 *@return array of items as returned by getItem
 */
function zCart_userapi_getItemsByCategory( $args )
{
    $result = pnModAPIFunc( 'zCart', 'user', 'readmultiplefromDB',
                                array( 'table' => 'items',
                                       'fields' => array( 'ItemID' ),
                                       'required' => array( 'Category', $args['CategoryID'] ) ) );
    $itemArray = array();
    if( $result <> false )
        {
            foreach( $result as $resultline )
            {
                list( $IID ) = $resultline;
                //permission check is done in getItem!
                $itemArray[$IID] = pnModAPIFunc( 'zCart', 'user', 'getItem', array( 'ItemID' => $IID ) );
            }
        }
     return $itemArray;
}

/**
 * AddLogMessage
 *
 *@params $args['level'] int loglevel
 *@params $args['text'] string message
 *returns nothing (why should we return anything? when we cannot log we cannot log this ;-) )
 */
function zCart_userapi_AddLogMessage( $args )
{
    extract( $args );
    if( isset( $level ) && isset( $text ) )
    {
        if( $level >= pnModGetVar( 'zCart', 'MaximumLogLevel' ) )
        {
            pnModDBInfoLoad('zCart');
            $pntable = pnDBGetTables();
            $logtable = $pntable['zcart_logs'];
            $logcolumn = &$pntable['zcart_logs_column'];
            $time = strftime( "%y-%m-%d %H:%M:%S" );
            $uname = pnSessionGetVar( 'PNCUser' );
            if( !isset($uname) )
            {
                $uname = _PNC_UNKNOWNUSER;
            }
            $uname = pnVarPrepForStore( $uname );
            $ip = $_SERVER['REMOTE_ADDR'];
            $text = pnVarPrepForStore( $text );

            $sql = "INSERT INTO $logtable
                    (
                      ".$logcolumn['timestamp'].",
                      ".$logcolumn['ip'].",
                      ".$logcolumn['username'].",
                      ".$logcolumn['level'].",
                      ".$logcolumn['text']."
                    )
                    VALUES
                        (
                            '".pnVarPrepForStore($time)."',
                            '".pnVarPrepForStore($ip)."',
                             '".pnVarPrepForStore($uname)."',
                             '".pnVarPrepForStore($level)."',
                             '".pnVarPrepForStore($text)."'
                         )";
            zCart_userapi_executesqlDB( array( 'sql' => $sql ) );
        }
    }
}

/**
 * manageCartItems
 *
 *newQty
 *ItemID
 *KID
 */
function zCart_userapi_manageCartItems( $args )
{
    extract( $args );
    $QUp = false;
	// only continue if the quantity field contains one of 0123456789
	if ( is_numeric ($newQty) == true )
	{
		//convert $newQty to int
		//We shoule make it possible to add doubles later
		$newQty = intval ( $newQty );
           	// get ItemQuantity, IgnoreQuantity and OrderedQuantity for this item
      	list($OnStock, $IgnoreQty, $OrderedQty, $CID) = zCart_userapi_readfromDB( array ('table' => 'items',  'required' => array ('ItemID', $ItemID), 'fields' => array ('ItemQuantity', 'IgnoreQuantity', 'QuantityOrdered', 'Category')));
		$FreeQty = $OnStock - $OrderedQty;

		if ( $Mode == "add" )
		{
            zCart_userapi_AddLogMessage( array( 'level' => _PNC_LOG_GENERAL, 'text' => "adding item id $ItemID to cart" ) );
			if( $newQty > 0 )
			{
				// we do not have a valid CartItemID, we get called from itemview
				// or itemlist, but the item maybe be in the cart already!!
		      	$result = zCart_userapi_readfromDB( array('table' => 'cartitems',
                  		                        'fields' => array('ItemQuantity', 'CartItemsID'),
                  	      		                'required' => array('ItemID', $ItemID, 'UserID', $KID)));
            	if ( $result != false )
            	{
            		// item is in cart
            		list($InCartQty, $CartItemID) = $result;
                	$InCartQty = intval($InCartQty);
                }
                else
                {
                	// item is not in cart
                	$InCartQty = 0;
                }
                if( $IgnoreQty != "on" )
                {
   			    	// we care about the item quantities
				    if ( $newQty >= $FreeQty )
      			    {
      			    	// we do not have enough on stock, so we have to
      			    	// adjust the quantity to what we have
      			    	$newCartQty = $InCartQty + $FreeQty;
      			    	// prepare the new QuantityOrdered
      			    	// in this case now everything on stock is covered by orders
      			    	$OrderedQty = $OnStock;
      			    	if( $newQty > $FreeQty )
      			    	{
      			    	    $QUp = true;
      			    	}
      			    }
      			    elseif( $newQty < $FreeQty )
      			    {
      			        // we have plenty on stock, best and most simple case
      			    	// prepare the new QuantityOrdered
      			    	$OrderedQty = $OrderedQty + $newQty;
				        $newCartQty = $InCartQty + $newQty;
				        $QUp = false;
				    }
			    }
			    else
			    {
			        // we dont care about the stock, just counting
			        $newCartQty = $InCartQty + $newQty;
			        $OrderedQty = $OrderedQty + $newQty;
			        $QUp = false;
			    }
				if ( $CartItemID )
				{
					// now we have the real newQty, lets update the db
		      		zCart_userapi_executesqlDB( array('sql' => "UPDATE ".pnConfigGetVar('prefix')."_zcart_cartitems
										SET ItemQuantity='".pnVarPrepForStore($newCartQty)."', Date='".time()."' WHERE CartItemsID='".pnVarPrepForStore($CartItemID)."' AND UserID='".pnVarPrepForStore($KID)."'"));
				}
				else
				{
					// no CartItemID - we add a new article to the cart
            		zCart_userapi_executesqlDB( array('sql' => "INSERT INTO ".pnConfigGetVar('prefix')."_zcart_cartitems (UserID, ItemID, ItemQuantity, Date, CartItemsID)
										  VALUES('".pnVarPrepForStore($KID)."', '".pnVarPrepForStore($ItemID)."', '".pnVarPrepForStore($newCartQty)."', '".time()."', '')"));
				}
           		// update the OrderedQty in the items table
				zCart_userapi_executesqlDB( array('sql' => "UPDATE ".pnConfigGetVar('prefix')."_zcart_items SET QuantityOrdered='".pnVarPrepForStore($OrderedQty)."' WHERE ItemID=".(int)pnVarPrepForStore($ItemID)));
			}
		}
		elseif( $Mode == "replace" )
		{
            zCart_userapi_AddLogMessage( array( 'level' => _PNC_LOG_GENERAL, 'text' => "updating item id $ItemID in cart" ) );
			if( $newQty > 0 )
			{
				// we have a valid CartItemID we can use, because we get called from the cartview
		      	$result = zCart_userapi_readfromDB( array('table' => 'cartitems',
                  		                        'fields' => array('ItemQuantity'),
                  	      		            'required' => array('CartItemsID', $CartItemID, 'UserID', $KID)));
            	if ( $result != false )
            	{
            		list($InCartQty) = $result;
                	$InCartQty = intval($InCartQty);

                }
                // before we start to replace the InCartQty with the newQty,  we undo the
                // adding of this item virtually (we remove the item from the cart and re-add
                // it afterwards
                $OrderedQty = $OrderedQty - $InCartQty;
                $FreeQty = $OnStock - $OrderedQty;
                $InCartQty = 0;

				if ( $IgnoreQty != "on" )
				{
      				// we care about the item quantitites
				    if( $newQty >= $FreeQty )
      			    {
      			    	// we care about the item quantitites AND
      			    	// we do not have enough on stock, so we have to
      			    	// adjust the quantity to what we have
				    	$newCartQty = $InCartQty + $FreeQty;
      			    	// prepare the new QuantityOrdered
      			    	// now the complete stock is covered by orders
      			    	$OrderedQty = $OnStock;
      			    	if( $newQty > $FreeQty )
				    	{
				    	    $QUp = true;
				        }
				    }
      			    elseif( $newQty < $FreeQty )
      			    {
      			        // we have plenty on stock, best and most simple case
      			    	// prepare the new QuantityOrdered
      			    	$OrderedQty = $OrderedQty + $newQty;
				        $newCartQty = $InCartQty + $newQty;
				        $QUp = false;
				    }
				}
				else
				{
			        // we dont care about the stock, just counting
			        $newCartQty = $InCartQty + $newQty;
			        $OrderedQty = $OrderedQty + $newQty;
			        $QUp = false;
				}
                // update the IQO in the items table
		      	zCart_userapi_executesqlDB( array('sql' => "UPDATE ".pnConfigGetVar('prefix')."_zcart_items SET QuantityOrdered='".pnVarPrepForStore($OrderedQty)."' WHERE ItemID=".(int)$ItemID));
				// now we have the real newQty, lets update the db
		      	zCart_userapi_executesqlDB(array('sql' => "UPDATE ".pnConfigGetVar('prefix')."_zcart_cartitems SET ItemQuantity='".pnVarPrepForStore($newCartQty)."', Date='".time()."' WHERE CartItemsID='".pnVarPrepForStore($CartItemID)."' AND UserID='".pnVarPrepForStore($KID)."'"));
			}
		}
		elseif( $Mode == "remove" )
		{
            zCart_userapi_AddLogMessage( array( 'level' => _PNC_LOG_GENERAL, 'text' => "removing item id $ItemID from cart" ) );
			// we have a valid CartItemID we can use, because we get called from the cartview
	        // no matter what $newQty is, we remove the item from the cart
	        zCart_userapi_removeItemFromCart( array( 'CartItemID' => $CartItemID,
	                             'KID'        => $KID ) );
		}
	}
	return $QUp;
}

?>